--- /dev/null
+/*
+* Copyright (c) 2007-2009 SlimDX Group
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*/
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+using SharpDX;
+using SharpDX.Direct3D9;
+using SharpDX.DXGI;
+using System.Diagnostics;
+
+using Rectangle = System.Drawing.Rectangle;
+
+namespace SampleFramework
+{
+ /// <summary>
+ /// Handles the configuration and management of the graphics device.
+ /// </summary>
+ public class GraphicsDeviceManager : IDisposable
+ {
+ Game game;
+ bool ignoreSizeChanges;
+ bool deviceLost;
+// bool doNotStoreBufferSize;
+// bool renderingOccluded;
+
+ int fullscreenWindowWidth;
+ int fullscreenWindowHeight;
+ int windowedWindowWidth;
+ int windowedWindowHeight;
+ WINDOWPLACEMENT windowedPlacement;
+ long windowedStyle;
+ bool savedTopmost;
+
+#if TEST_Direct3D9Ex
+ internal static Direct3DEx Direct3D9Object // yyagi
+#else
+ internal static Direct3D Direct3D9Object
+#endif
+ {
+ get;
+ private set;
+ }
+
+ public DeviceSettings CurrentSettings
+ {
+ get;
+ private set;
+ }
+ public bool IsWindowed
+ {
+ get { return CurrentSettings.Windowed; }
+ }
+ public int ScreenWidth
+ {
+ get { return CurrentSettings.BackBufferWidth; }
+ }
+ public int ScreenHeight
+ {
+ get { return CurrentSettings.BackBufferHeight; }
+ }
+ public Size ScreenSize
+ {
+ get { return new Size(CurrentSettings.BackBufferWidth, CurrentSettings.BackBufferHeight); }
+ }
+ public Direct3D9Manager Direct3D9
+ {
+ get;
+ private set;
+ }
+ public string DeviceStatistics
+ {
+ get;
+ private set;
+ }
+ public string DeviceInformation
+ {
+ get;
+ private set;
+ }
+
+ public GraphicsDeviceManager( Game game )
+ {
+ if( game == null )
+ throw new ArgumentNullException( "game" );
+
+ this.game = game;
+
+ game.Window.ScreenChanged += Window_ScreenChanged;
+ game.Window.UserResized += Window_UserResized;
+
+ game.FrameStart += game_FrameStart;
+ game.FrameEnd += game_FrameEnd;
+
+ Direct3D9 = new Direct3D9Manager( this );
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public void ChangeDevice( DeviceSettings settings, DeviceSettings minimumSettings )
+ {
+ if( settings == null )
+ throw new ArgumentNullException( "settings" );
+
+ Enumeration9.MinimumSettings = minimumSettings;
+
+ DeviceSettings validSettings = DeviceSettings.FindValidSettings( settings );
+
+ var pp = validSettings.Direct3D9.PresentParameters;
+ pp.DeviceWindowHandle = game.Window.Handle;
+ validSettings.Direct3D9.PresentParameters = pp;
+
+ CreateDevice( validSettings );
+ }
+ public void ChangeDevice(bool windowed, int desiredWidth, int desiredHeight)
+ {
+ DeviceSettings desiredSettings = new DeviceSettings();
+ desiredSettings.Windowed = windowed;
+ desiredSettings.BackBufferWidth = desiredWidth;
+ desiredSettings.BackBufferHeight = desiredHeight;
+
+ ChangeDevice(desiredSettings, null);
+ }
+ public void ChangeDevice(DeviceSettings settings)
+ {
+ ChangeDevice(settings, null);
+ }
+
+ public void ToggleFullScreen()
+ {
+ if (!EnsureDevice())
+ throw new InvalidOperationException("No valid device.");
+
+ DeviceSettings newSettings = CurrentSettings.Clone();
+
+ newSettings.Windowed = !newSettings.Windowed;
+
+ int width = newSettings.Windowed ? windowedWindowWidth : fullscreenWindowWidth;
+ int height = newSettings.Windowed ? windowedWindowHeight : fullscreenWindowHeight;
+
+ newSettings.BackBufferWidth = width;
+ newSettings.BackBufferHeight = height;
+
+ ChangeDevice(newSettings);
+ }
+ public bool EnsureDevice()
+ {
+ if (Direct3D9.Device != null && !deviceLost)
+ return true;
+
+ return false;
+ }
+
+ protected virtual void Dispose( bool disposing )
+ {
+ if( this.bDisposed )
+ return;
+ this.bDisposed = true;
+
+ if( disposing )
+ ReleaseDevice();
+
+ }
+ private bool bDisposed = false;
+
+ void CreateDevice(DeviceSettings settings)
+ {
+ DeviceSettings oldSettings = CurrentSettings;
+ CurrentSettings = settings;
+
+ ignoreSizeChanges = true;
+
+ bool keepCurrentWindowSize = false;
+ if (settings.BackBufferWidth == 0 && settings.BackBufferHeight == 0)
+ keepCurrentWindowSize = true;
+
+ // handle the window state in Direct3D9 (it will be handled for us in DXGI)
+ // check if we are going to windowed or fullscreen mode
+ if( settings.Windowed )
+ {
+ if( oldSettings != null && !oldSettings.Windowed )
+ NativeMethods.SetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE, (uint) windowedStyle );
+ }
+ else
+ {
+ if( oldSettings == null || oldSettings.Windowed )
+ {
+ savedTopmost = game.Window.TopMost;
+ long style = NativeMethods.GetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE );
+ style &= ~WindowConstants.WS_MAXIMIZE & ~WindowConstants.WS_MINIMIZE;
+ windowedStyle = style;
+
+ windowedPlacement = new WINDOWPLACEMENT();
+ windowedPlacement.length = WINDOWPLACEMENT.Length;
+ NativeMethods.GetWindowPlacement( game.Window.Handle, ref windowedPlacement );
+ }
+
+ // hide the window until we are done messing with it
+ game.Window.Hide();
+ NativeMethods.SetWindowLong( game.Window.Handle, WindowConstants.GWL_STYLE, (uint) ( WindowConstants.WS_POPUP | WindowConstants.WS_SYSMENU ) );
+
+ WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
+ placement.length = WINDOWPLACEMENT.Length;
+ NativeMethods.GetWindowPlacement( game.Window.Handle, ref placement );
+
+ // check if we are in the middle of a restore
+ if( ( placement.flags & WindowConstants.WPF_RESTORETOMAXIMIZED ) != 0 )
+ {
+ // update the flags to avoid sizing issues
+ placement.flags &= ~WindowConstants.WPF_RESTORETOMAXIMIZED;
+ placement.showCmd = WindowConstants.SW_RESTORE;
+ NativeMethods.SetWindowPlacement( game.Window.Handle, ref placement );
+ }
+ }
+
+ if (settings.Windowed)
+ {
+ if (oldSettings != null && !oldSettings.Windowed)
+ {
+ fullscreenWindowWidth = oldSettings.BackBufferWidth;
+ fullscreenWindowHeight = oldSettings.BackBufferHeight;
+ }
+ }
+ else
+ {
+ if (oldSettings != null && oldSettings.Windowed)
+ {
+ windowedWindowWidth = oldSettings.BackBufferWidth;
+ windowedWindowHeight = oldSettings.BackBufferHeight;
+ }
+ }
+
+ // check if the device can be reset, or if we need to completely recreate it
+ Result result = SharpDX.Direct3D9.ResultCode.Success;
+ bool canReset = CanDeviceBeReset(oldSettings, settings);
+ if (canReset)
+ result = ResetDevice();
+
+ if (result == SharpDX.Direct3D9.ResultCode.DeviceLost)
+ deviceLost = true;
+ else if (!canReset || result.Failure)
+ {
+ if (oldSettings != null)
+ ReleaseDevice();
+
+ InitializeDevice();
+ }
+
+ UpdateDeviceInformation();
+
+ // check if we changed from fullscreen to windowed mode
+ if (oldSettings != null && !oldSettings.Windowed && settings.Windowed)
+ {
+ NativeMethods.SetWindowPlacement(game.Window.Handle, ref windowedPlacement);
+ game.Window.TopMost = savedTopmost;
+ }
+
+ // check if we need to resize
+ if (settings.Windowed && !keepCurrentWindowSize)
+ {
+ int width;
+ int height;
+ if (NativeMethods.IsIconic(game.Window.Handle))
+ {
+ WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
+ placement.length = WINDOWPLACEMENT.Length;
+ NativeMethods.GetWindowPlacement(game.Window.Handle, ref placement);
+
+ // check if we are being restored
+ if ((placement.flags & WindowConstants.WPF_RESTORETOMAXIMIZED) != 0 && placement.showCmd == WindowConstants.SW_SHOWMINIMIZED)
+ {
+ NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
+
+ Rectangle rect = NativeMethods.GetClientRectangle(game.Window.Handle);
+
+ width = rect.Width;
+ height = rect.Height;
+ NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_MINIMIZE);
+ }
+ else
+ {
+ NativeRectangle frame = new NativeRectangle();
+ NativeMethods.AdjustWindowRect(ref frame, (uint)windowedStyle, false);
+ int frameWidth = frame.right - frame.left;
+ int frameHeight = frame.bottom - frame.top;
+
+ width = placement.rcNormalPosition.right - placement.rcNormalPosition.left - frameWidth;
+ height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top - frameHeight;
+ }
+ }
+ else
+ {
+ Rectangle rect = NativeMethods.GetClientRectangle(game.Window.Handle);
+ width = rect.Width;
+ height = rect.Height;
+ }
+
+ // check if we have a different desired size
+ if (width != settings.BackBufferWidth ||
+ height != settings.BackBufferHeight)
+ {
+ if (NativeMethods.IsIconic(game.Window.Handle))
+ NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
+ if (NativeMethods.IsZoomed(game.Window.Handle))
+ NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_RESTORE);
+
+ NativeRectangle rect = new NativeRectangle();
+ rect.right = settings.BackBufferWidth;
+ rect.bottom = settings.BackBufferHeight;
+ NativeMethods.AdjustWindowRect(ref rect,
+ NativeMethods.GetWindowLong(game.Window.Handle, WindowConstants.GWL_STYLE), false);
+
+ NativeMethods.SetWindowPos(game.Window.Handle, IntPtr.Zero, 0, 0, rect.right - rect.left,
+ rect.bottom - rect.top, WindowConstants.SWP_NOZORDER | WindowConstants.SWP_NOMOVE);
+
+ Rectangle r = NativeMethods.GetClientRectangle(game.Window.Handle);
+ int clientWidth = r.Width;
+ int clientHeight = r.Height;
+
+ // check if the size was modified by Windows
+ if (clientWidth != settings.BackBufferWidth ||
+ clientHeight != settings.BackBufferHeight)
+ {
+ DeviceSettings newSettings = CurrentSettings.Clone();
+ newSettings.BackBufferWidth = 0;
+ newSettings.BackBufferHeight = 0;
+ if (newSettings.Direct3D9 != null)
+ {
+ var pp = newSettings.Direct3D9.PresentParameters;
+ pp.BackBufferWidth = GameWindowSize.Width; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
+ pp.BackBufferHeight = GameWindowSize.Height; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
+ newSettings.Direct3D9.PresentParameters = pp;
+ }
+
+ CreateDevice(newSettings);
+ }
+ }
+ }
+
+ // if the window is still hidden, make sure it is shown
+ if (!game.Window.Visible)
+ NativeMethods.ShowWindow(game.Window.Handle, WindowConstants.SW_SHOW);
+
+ // set the execution state of the thread
+ if (!IsWindowed)
+ NativeMethods.SetThreadExecutionState(WindowConstants.ES_DISPLAY_REQUIRED | WindowConstants.ES_CONTINUOUS);
+ else
+ NativeMethods.SetThreadExecutionState(WindowConstants.ES_CONTINUOUS);
+
+ ignoreSizeChanges = false;
+ }
+
+ void Window_UserResized( object sender, EventArgs e )
+ {
+ if( ignoreSizeChanges || !EnsureDevice() || ( !IsWindowed ) )
+ return;
+
+ DeviceSettings newSettings = CurrentSettings.Clone();
+
+ Rectangle rect = NativeMethods.GetClientRectangle( game.Window.Handle );
+ if( rect.Width != newSettings.BackBufferWidth || rect.Height != newSettings.BackBufferHeight )
+ {
+ newSettings.BackBufferWidth = 0;
+ newSettings.BackBufferHeight = 0;
+ var pp = newSettings.Direct3D9.PresentParameters;
+ pp.BackBufferWidth = GameWindowSize.Width; // #23510 2010.10.31 add yyagi: to avoid setting BackBufferSize=ClientSize
+ pp.BackBufferHeight = GameWindowSize.Height; //
+ newSettings.Direct3D9.PresentParameters = pp;
+ CreateDevice( newSettings );
+ }
+ }
+ void Window_ScreenChanged( object sender, EventArgs e )
+ {
+ if( !EnsureDevice() || !CurrentSettings.Windowed || ignoreSizeChanges )
+ return;
+
+ IntPtr windowMonitor = NativeMethods.MonitorFromWindow( game.Window.Handle, WindowConstants.MONITOR_DEFAULTTOPRIMARY );
+
+ DeviceSettings newSettings = CurrentSettings.Clone();
+ int adapterOrdinal = GetAdapterOrdinal( windowMonitor );
+ if( adapterOrdinal == -1 )
+ return;
+ newSettings.Direct3D9.AdapterOrdinal = adapterOrdinal;
+
+ newSettings.BackBufferWidth = 0; // #23510 2010.11.1 add yyagi to avoid to reset to 640x480 for the first time in XP.
+ newSettings.BackBufferHeight = 0; //
+ var pp = newSettings.Direct3D9.PresentParameters;
+ pp.BackBufferWidth = GameWindowSize.Width; //
+ pp.BackBufferHeight = GameWindowSize.Height; //
+ newSettings.Direct3D9.PresentParameters = pp;
+
+ CreateDevice( newSettings);
+ }
+
+ void game_FrameEnd( object sender, EventArgs e )
+ {
+ Result result = SharpDX.Direct3D9.ResultCode.Success;
+
+ try
+ {
+ //result = Direct3D9.Device.TestCooperativeLevel();
+ Direct3D9.Device.Present();
+ }
+ catch // #23842 2011.1.6 yyagi: catch D3D9Exception to avoid unexpected termination by changing VSyncWait in fullscreen.
+ {
+ deviceLost = true;
+ }
+
+ if( result == SharpDX.Direct3D9.ResultCode.DeviceLost )
+ deviceLost = true;
+ }
+ void game_FrameStart(object sender, CancelEventArgs e)
+ {
+ if (Direct3D9.Device == null )
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ //if (!game.IsActive || deviceLost) // #23568 2010.11.3 yyagi: separate conditions to support valiable sleep value when !IsActive.
+ if( deviceLost )
+ Thread.Sleep( 50 );
+ else if( !game.IsActive && !this.CurrentSettings.EnableVSync ) // #23568 2010.11.4 yyagi: Don't add sleep() while VSync is enabled.
+ Thread.Sleep( this.game.InactiveSleepTime.Milliseconds );
+
+ if (deviceLost)
+ {
+ Result result = Direct3D9.Device.TestCooperativeLevel();
+ if (result == SharpDX.Direct3D9.ResultCode.DeviceLost)
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ // if we are windowed, check the adapter format to see if the user
+ // changed the desktop format, causing a lost device
+ if (IsWindowed)
+ {
+ DisplayMode displayMode = GraphicsDeviceManager.Direct3D9Object.GetAdapterDisplayMode(CurrentSettings.Direct3D9.AdapterOrdinal);
+ if (CurrentSettings.Direct3D9.AdapterFormat != displayMode.Format)
+ {
+ DeviceSettings newSettings = CurrentSettings.Clone();
+ ChangeDevice(newSettings);
+ e.Cancel = true;
+ return;
+ }
+ }
+
+ result = ResetDevice();
+ if (result.Failure)
+ {
+ e.Cancel = true;
+ return;
+ }
+ }
+
+ deviceLost = false;
+ }
+
+ bool CanDeviceBeReset( DeviceSettings oldSettings, DeviceSettings newSettings )
+ {
+ if( oldSettings == null )
+ return false;
+
+ return Direct3D9.Device != null &&
+ oldSettings.Direct3D9.AdapterOrdinal == newSettings.Direct3D9.AdapterOrdinal &&
+ oldSettings.Direct3D9.DeviceType == newSettings.Direct3D9.DeviceType &&
+ oldSettings.Direct3D9.CreationFlags == newSettings.Direct3D9.CreationFlags;
+ }
+
+ void InitializeDevice()
+ {
+ try
+ {
+ EnsureD3D9();
+
+#if TEST_Direct3D9Ex
+ // 2011.4.26 yyagi
+ // Direct3D9.DeviceExを呼ぶ際(IDirect3D9Ex::CreateDeviceExを呼ぶ際)、
+ // フルスクリーンモードで初期化する場合はDisplayModeEx(D3DDISPLAYMODEEX *pFullscreenDisplayMode)に
+ // 適切な値を設定する必要あり。
+ // 一方、ウインドウモードで初期化する場合は、D3DDISPLAYMODEEXをNULLにする必要があるが、
+ // DisplayModeExがNULL不可と定義されているため、DeviceExのoverloadの中でDisplayModeExを引数に取らないものを
+ // 使う。(DeviceEx側でD3DDISPLAYMODEEXをNULLにしてくれる)
+ // 結局、DeviceExの呼び出しの際に、フルスクリーンかどうかで場合分けが必要となる。
+ if ( CurrentSettings.Direct3D9.PresentParameters.Windowed == false )
+ {
+ DisplayModeEx fullScreenDisplayMode = new DisplayModeEx();
+ fullScreenDisplayMode.Width = CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth;
+ fullScreenDisplayMode.Height = CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight;
+ fullScreenDisplayMode.RefreshRate = CurrentSettings.Direct3D9.PresentParameters.FullScreenRefreshRateInHertz;
+ fullScreenDisplayMode.Format = CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat;
+
+ Direct3D9.Device = new SlimDX.Direct3D9.DeviceEx( Direct3D9Object, CurrentSettings.Direct3D9.AdapterOrdinal,
+ CurrentSettings.Direct3D9.DeviceType, game.Window.Handle,
+ CurrentSettings.Direct3D9.CreationFlags, CurrentSettings.Direct3D9.PresentParameters, fullScreenDisplayMode );
+ }
+ else
+ {
+ Direct3D9.Device = new SlimDX.Direct3D9.DeviceEx( Direct3D9Object, CurrentSettings.Direct3D9.AdapterOrdinal,
+ CurrentSettings.Direct3D9.DeviceType, game.Window.Handle,
+ CurrentSettings.Direct3D9.CreationFlags, CurrentSettings.Direct3D9.PresentParameters );
+ }
+ Direct3D9.Device.MaximumFrameLatency = 1;
+#else
+ Direct3D9.Device = new SharpDX.Direct3D9.Device(
+ Direct3D9Object,
+ CurrentSettings.Direct3D9.AdapterOrdinal,
+ CurrentSettings.Direct3D9.DeviceType,
+ game.Window.Handle,
+ CurrentSettings.Direct3D9.CreationFlags,
+ CurrentSettings.Direct3D9.PresentParameters );
+#endif
+ if ( Result.GetResultFromWin32Error( Marshal.GetLastWin32Error() ) == SharpDX.Direct3D9.ResultCode.DeviceLost )
+ {
+ deviceLost = true;
+ return;
+ }
+#if TEST_Direct3D9Ex
+ Direct3D9.Device.MaximumFrameLatency = 1; // yyagi
+#endif
+ }
+ catch( Exception e )
+ {
+ throw new DeviceCreationException( "Could not create graphics device.", e );
+ }
+
+ PropogateSettings();
+
+ UpdateDeviceStats();
+
+ game.Initialize();
+ game.LoadContent();
+ }
+
+ Result ResetDevice()
+ {
+ game.UnloadContent();
+
+ Direct3D9.Device.Reset( CurrentSettings.Direct3D9.PresentParameters );
+
+ var result = Result.GetResultFromWin32Error( Marshal.GetLastWin32Error() );
+
+ if( result == SharpDX.Direct3D9.ResultCode.DeviceLost )
+ return result;
+
+ PropogateSettings();
+ UpdateDeviceStats();
+ game.LoadContent();
+
+ return result;
+ }
+
+ void ReleaseDevice()
+ {
+ ReleaseDevice9();
+ }
+
+ void ReleaseDevice9()
+ {
+ if (Direct3D9.Device == null)
+ return;
+
+ if (game != null)
+ {
+ game.UnloadContent();
+ game.Dispose(true);
+ }
+
+ try
+ {
+ Direct3D9.Device.Dispose();
+ }
+ catch( ObjectDisposedException )
+ {
+ // 時々発生するのでキャッチしておく。
+ }
+ Direct3D9Object.Dispose();
+
+ Direct3D9Object = null;
+ Direct3D9.Device = null;
+ }
+ void PropogateSettings()
+ {
+ CurrentSettings.BackBufferCount = CurrentSettings.Direct3D9.PresentParameters.BackBufferCount;
+ CurrentSettings.BackBufferWidth = CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth;
+ CurrentSettings.BackBufferHeight = CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight;
+ CurrentSettings.BackBufferFormat = CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat;
+ CurrentSettings.DepthStencilFormat = CurrentSettings.Direct3D9.PresentParameters.AutoDepthStencilFormat;
+ CurrentSettings.DeviceType = CurrentSettings.Direct3D9.DeviceType;
+ CurrentSettings.MultisampleQuality = CurrentSettings.Direct3D9.PresentParameters.MultiSampleQuality;
+ CurrentSettings.MultisampleType = CurrentSettings.Direct3D9.PresentParameters.MultiSampleType;
+ CurrentSettings.RefreshRate = CurrentSettings.Direct3D9.PresentParameters.FullScreenRefreshRateInHz;
+ CurrentSettings.Windowed = CurrentSettings.Direct3D9.PresentParameters.Windowed;
+ }
+
+ void UpdateDeviceInformation()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
+ builder.Append( "HAL" );
+ else if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Reference )
+ builder.Append( "REF" );
+ else if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Software )
+ builder.Append( "SW" );
+
+ if( ( CurrentSettings.Direct3D9.CreationFlags & CreateFlags.HardwareVertexProcessing ) != 0 )
+ if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
+ builder.Append( " (hw vp)" );
+ else
+ builder.Append( " (simulated hw vp)" );
+ else if( ( CurrentSettings.Direct3D9.CreationFlags & CreateFlags.MixedVertexProcessing ) != 0 )
+ if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
+ builder.Append( " (mixed vp)" );
+ else
+ builder.Append( " (simulated mixed vp)" );
+ else
+ builder.Append( " (sw vp)" );
+
+ if( CurrentSettings.Direct3D9.DeviceType == DeviceType.Hardware )
+ {
+ // loop through each adapter until we find the right one
+ foreach( AdapterInfo9 adapterInfo in Enumeration9.Adapters )
+ {
+ if( adapterInfo.AdapterOrdinal == CurrentSettings.Direct3D9.AdapterOrdinal )
+ {
+ builder.AppendFormat( ": {0}", adapterInfo.Description );
+ break;
+ }
+ }
+ }
+
+ DeviceInformation = builder.ToString();
+ }
+
+ void UpdateDeviceStats()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ builder.Append( "D3D9 Vsync " );
+
+ if( CurrentSettings.Direct3D9.PresentParameters.PresentationInterval == PresentInterval.Immediate )
+ builder.Append( "off" );
+ else
+ builder.Append( "on" );
+
+ builder.AppendFormat( " ({0}x{1}), ", CurrentSettings.Direct3D9.PresentParameters.BackBufferWidth, CurrentSettings.Direct3D9.PresentParameters.BackBufferHeight );
+
+ if( CurrentSettings.Direct3D9.AdapterFormat == CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat )
+ builder.Append( Enum.GetName( typeof( SharpDX.Direct3D9.Format ), CurrentSettings.Direct3D9.AdapterFormat ) );
+ else
+ builder.AppendFormat( "backbuf {0}, adapter {1}",
+ Enum.GetName( typeof( SharpDX.Direct3D9.Format ), CurrentSettings.Direct3D9.AdapterFormat ),
+ Enum.GetName( typeof( SharpDX.Direct3D9.Format ), CurrentSettings.Direct3D9.PresentParameters.BackBufferFormat ) );
+
+ builder.AppendFormat( " ({0})", Enum.GetName( typeof( SharpDX.Direct3D9.Format ), CurrentSettings.Direct3D9.PresentParameters.AutoDepthStencilFormat ) );
+
+ if( CurrentSettings.Direct3D9.PresentParameters.MultiSampleType == MultisampleType.NonMaskable )
+ builder.Append( " (Nonmaskable Multisample)" );
+ else if( CurrentSettings.Direct3D9.PresentParameters.MultiSampleType != MultisampleType.None )
+ builder.AppendFormat( " ({0}x Multisample)", (int) CurrentSettings.Direct3D9.PresentParameters.MultiSampleQuality );
+
+ DeviceStatistics = builder.ToString();
+ }
+
+ int GetAdapterOrdinal( IntPtr screen )
+ {
+ AdapterInfo9 adapter = null;
+ foreach( AdapterInfo9 a in Enumeration9.Adapters )
+ {
+ if( Direct3D9Object.GetAdapterMonitor( a.AdapterOrdinal ) == screen )
+ {
+ adapter = a;
+ break;
+ }
+ }
+
+ if( adapter != null )
+ return adapter.AdapterOrdinal;
+
+ return -1;
+ }
+
+ internal static void EnsureD3D9()
+ {
+ if ( Direct3D9Object == null )
+#if TEST_Direct3D9Ex
+ Direct3D9Object = new Direct3DEx(); // yyagi
+#else
+ Direct3D9Object = new Direct3D();
+#endif
+ }
+ }
+}