//-------------------------------------------------------------------------------------- // File: DXUT.cpp // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // // http://go.microsoft.com/fwlink/?LinkId=320437 //-------------------------------------------------------------------------------------- #include "DXUT.h" #ifndef NDEBUG #include #endif #define DXUT_MIN_WINDOW_SIZE_X 200 #define DXUT_MIN_WINDOW_SIZE_Y 200 #define DXUT_COUNTER_STAT_LENGTH 2048 //-------------------------------------------------------------------------------------- // Thread safety //-------------------------------------------------------------------------------------- CRITICAL_SECTION g_cs; bool g_bThreadSafe = true; //-------------------------------------------------------------------------------------- // Automatically enters & leaves the CS upon object creation/deletion //-------------------------------------------------------------------------------------- class DXUTLock { public: #pragma prefast( suppress:26166, "g_bThreadSafe controls behavior" ) inline _Acquires_lock_(g_cs) DXUTLock() { if( g_bThreadSafe ) EnterCriticalSection( &g_cs ); } #pragma prefast( suppress:26165, "g_bThreadSafe controls behavior" ) inline _Releases_lock_(g_cs) ~DXUTLock() { if( g_bThreadSafe ) LeaveCriticalSection( &g_cs ); } }; //-------------------------------------------------------------------------------------- // Helper macros to build member functions that access member variables with thread safety //-------------------------------------------------------------------------------------- #define SET_ACCESSOR( x, y ) inline void Set##y( x t ) { DXUTLock l; m_state.m_##y = t; }; #define GET_ACCESSOR( x, y ) inline x Get##y() { DXUTLock l; return m_state.m_##y; }; #define GET_SET_ACCESSOR( x, y ) SET_ACCESSOR( x, y ) GET_ACCESSOR( x, y ) #define SETP_ACCESSOR( x, y ) inline void Set##y( x* t ) { DXUTLock l; m_state.m_##y = *t; }; #define GETP_ACCESSOR( x, y ) inline x* Get##y() { DXUTLock l; return &m_state.m_##y; }; #define GETP_SETP_ACCESSOR( x, y ) SETP_ACCESSOR( x, y ) GETP_ACCESSOR( x, y ) //-------------------------------------------------------------------------------------- // Stores timer callback info //-------------------------------------------------------------------------------------- struct DXUT_TIMER { LPDXUTCALLBACKTIMER pCallbackTimer; void* pCallbackUserContext; float fTimeoutInSecs; float fCountdown; bool bEnabled; UINT nID; }; //-------------------------------------------------------------------------------------- // Stores DXUT state and data access is done with thread safety (if g_bThreadSafe==true) //-------------------------------------------------------------------------------------- class DXUTState { protected: struct STATE { DXUTDeviceSettings* m_CurrentDeviceSettings; // current device settings IDXGIFactory1* m_DXGIFactory; // DXGI Factory object IDXGIAdapter1* m_DXGIAdapter; // The DXGI adapter object for the D3D11 device IDXGIOutput** m_DXGIOutputArray; // The array of output obj for the D3D11 adapter obj UINT m_DXGIOutputArraySize; // Number of elements in m_D3D11OutputArray IDXGISwapChain* m_DXGISwapChain; // the D3D11 swapchain DXGI_SURFACE_DESC m_BackBufferSurfaceDescDXGI; // D3D11 back buffer surface description bool m_RenderingOccluded; // Rendering is occluded by another window bool m_DoNotStoreBufferSize; // Do not store the buffer size on WM_SIZE messages // D3D11 specific ID3D11Device* m_D3D11Device; // the D3D11 rendering device ID3D11DeviceContext* m_D3D11DeviceContext; // the D3D11 immediate device context D3D_FEATURE_LEVEL m_D3D11FeatureLevel; // the D3D11 feature level that this device supports ID3D11Texture2D* m_D3D11DepthStencil; // the D3D11 depth stencil texture (optional) ID3D11DepthStencilView* m_D3D11DepthStencilView; // the D3D11 depth stencil view (optional) ID3D11RenderTargetView* m_D3D11RenderTargetView; // the D3D11 render target view ID3D11RasterizerState* m_D3D11RasterizerState; // the D3D11 Rasterizer state // D3D11.1 specific ID3D11Device1* m_D3D11Device1; // the D3D11.1 rendering device ID3D11DeviceContext1* m_D3D11DeviceContext1; // the D3D11.1 immediate device context #ifdef USE_DIRECT3D11_2 // D3D11.2 specific ID3D11Device2* m_D3D11Device2; // the D3D11.2 rendering device ID3D11DeviceContext2* m_D3D11DeviceContext2; // the D3D11.2 immediate device context #endif #ifdef USE_DIRECT3D11_3 // D3D11.3 specific ID3D11Device3* m_D3D11Device3; // the D3D11.3 rendering device ID3D11DeviceContext3* m_D3D11DeviceContext3; // the D3D11.3 immediate device context #endif // General HWND m_HWNDFocus; // the main app focus window HWND m_HWNDDeviceFullScreen; // the main app device window in fullscreen mode HWND m_HWNDDeviceWindowed; // the main app device window in windowed mode HMONITOR m_AdapterMonitor; // the monitor of the adapter HMENU m_Menu; // handle to menu UINT m_FullScreenBackBufferWidthAtModeChange; // back buffer size of fullscreen mode right before switching to windowed mode. Used to restore to same resolution when toggling back to fullscreen UINT m_FullScreenBackBufferHeightAtModeChange; // back buffer size of fullscreen mode right before switching to windowed mode. Used to restore to same resolution when toggling back to fullscreen UINT m_WindowBackBufferWidthAtModeChange; // back buffer size of windowed mode right before switching to fullscreen mode. Used to restore to same resolution when toggling back to windowed mode UINT m_WindowBackBufferHeightAtModeChange; // back buffer size of windowed mode right before switching to fullscreen mode. Used to restore to same resolution when toggling back to windowed mode DWORD m_WindowedStyleAtModeChange; // window style WINDOWPLACEMENT m_WindowedPlacement;// record of windowed HWND position/show state/etc bool m_TopmostWhileWindowed; // if true, the windowed HWND is topmost bool m_Minimized; // if true, the HWND is minimized bool m_Maximized; // if true, the HWND is maximized bool m_MinimizedWhileFullscreen; // if true, the HWND is minimized due to a focus switch away when fullscreen mode bool m_IgnoreSizeChange; // if true, DXUT won't reset the device upon HWND size change double m_Time; // current time in seconds double m_AbsoluteTime; // absolute time in seconds float m_ElapsedTime; // time elapsed since last frame HINSTANCE m_HInstance; // handle to the app instance double m_LastStatsUpdateTime; // last time the stats were updated DWORD m_LastStatsUpdateFrames; // frames count since last time the stats were updated float m_FPS; // frames per second int m_CurrentFrameNumber; // the current frame number HHOOK m_KeyboardHook; // handle to keyboard hook bool m_AllowShortcutKeysWhenFullscreen; // if true, when fullscreen enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) bool m_AllowShortcutKeysWhenWindowed; // if true, when windowed enable shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) bool m_AllowShortcutKeys; // if true, then shortcut keys are currently disabled (Windows key, etc) bool m_CallDefWindowProc; // if true, DXUTStaticWndProc will call DefWindowProc for unhandled messages. Applications rendering to a dialog may need to set this to false. STICKYKEYS m_StartupStickyKeys; // StickyKey settings upon startup so they can be restored later TOGGLEKEYS m_StartupToggleKeys; // ToggleKey settings upon startup so they can be restored later FILTERKEYS m_StartupFilterKeys; // FilterKey settings upon startup so they can be restored later bool m_HandleEscape; // if true, then DXUT will handle escape to quit bool m_HandleAltEnter; // if true, then DXUT will handle alt-enter to toggle fullscreen bool m_HandlePause; // if true, then DXUT will handle pause to toggle time pausing bool m_ShowMsgBoxOnError; // if true, then msgboxes are displayed upon errors bool m_NoStats; // if true, then DXUTGetFrameStats() and DXUTGetDeviceStats() will return blank strings bool m_ClipCursorWhenFullScreen; // if true, then DXUT will keep the cursor from going outside the window when full screen bool m_ShowCursorWhenFullScreen; // if true, then DXUT will show a cursor when full screen bool m_ConstantFrameTime; // if true, then elapsed frame time will always be 0.05f seconds which is good for debugging or automated capture float m_TimePerFrame; // the constant time per frame in seconds, only valid if m_ConstantFrameTime==true bool m_WireframeMode; // if true, then D3DRS_FILLMODE==D3DFILL_WIREFRAME else D3DRS_FILLMODE==D3DFILL_SOLID bool m_AutoChangeAdapter; // if true, then the adapter will automatically change if the window is different monitor bool m_WindowCreatedWithDefaultPositions; // if true, then CW_USEDEFAULT was used and the window should be moved to the right adapter int m_ExitCode; // the exit code to be returned to the command line bool m_DXUTInited; // if true, then DXUTInit() has succeeded bool m_WindowCreated; // if true, then DXUTCreateWindow() or DXUTSetWindow() has succeeded bool m_DeviceCreated; // if true, then DXUTCreateDevice() has succeeded bool m_DXUTInitCalled; // if true, then DXUTInit() was called bool m_WindowCreateCalled; // if true, then DXUTCreateWindow() or DXUTSetWindow() was called bool m_DeviceCreateCalled; // if true, then DXUTCreateDevice() was called bool m_DeviceObjectsCreated; // if true, then DeviceCreated callback has been called (if non-NULL) bool m_DeviceObjectsReset; // if true, then DeviceReset callback has been called (if non-NULL) bool m_InsideDeviceCallback; // if true, then the framework is inside an app device callback bool m_InsideMainloop; // if true, then the framework is inside the main loop bool m_Active; // if true, then the app is the active top level window bool m_TimePaused; // if true, then time is paused bool m_RenderingPaused; // if true, then rendering is paused int m_PauseRenderingCount; // pause rendering ref count int m_PauseTimeCount; // pause time ref count bool m_DeviceLost; // if true, then the device is lost and needs to be reset bool m_NotifyOnMouseMove; // if true, include WM_MOUSEMOVE in mousecallback bool m_Automation; // if true, automation is enabled bool m_InSizeMove; // if true, app is inside a WM_ENTERSIZEMOVE UINT m_TimerLastID; // last ID of the DXUT timer bool m_MessageWhenD3D11NotAvailable; D3D_FEATURE_LEVEL m_OverrideForceFeatureLevel; // if != -1, then overrid to use a featurelevel WCHAR m_ScreenShotName[256]; // command line screen shot name bool m_SaveScreenShot; // command line save screen shot bool m_ExitAfterScreenShot; // command line exit after screen shot int m_OverrideAdapterOrdinal; // if != -1, then override to use this adapter ordinal bool m_OverrideWindowed; // if true, then force to start windowed int m_OverrideOutput; // if != -1, then override to use the particular output on the adapter bool m_OverrideFullScreen; // if true, then force to start full screen int m_OverrideStartX; // if != -1, then override to this X position of the window int m_OverrideStartY; // if != -1, then override to this Y position of the window int m_OverrideWidth; // if != 0, then override to this width int m_OverrideHeight; // if != 0, then override to this height bool m_OverrideForceHAL; // if true, then force to HAL device (failing if one doesn't exist) bool m_OverrideForceREF; // if true, then force to REF device (failing if one doesn't exist) bool m_OverrideForceWARP; // if true, then force to WARP device (failing if one doesn't exist) bool m_OverrideConstantFrameTime; // if true, then force to constant frame time float m_OverrideConstantTimePerFrame; // the constant time per frame in seconds if m_OverrideConstantFrameTime==true int m_OverrideQuitAfterFrame; // if != 0, then it will force the app to quit after that frame int m_OverrideForceVsync; // if == 0, then it will force the app to use D3DPRESENT_INTERVAL_IMMEDIATE, if == 1 force use of D3DPRESENT_INTERVAL_DEFAULT bool m_AppCalledWasKeyPressed; // true if the app ever calls DXUTWasKeyPressed(). Allows for optimzation bool m_ReleasingSwapChain; // if true, the app is releasing its swapchain bool m_IsInGammaCorrectMode; // Tell DXUTRes and DXUTMisc that we are in gamma correct mode LPDXUTCALLBACKMODIFYDEVICESETTINGS m_ModifyDeviceSettingsFunc; // modify Direct3D device settings callback LPDXUTCALLBACKDEVICEREMOVED m_DeviceRemovedFunc; // Direct3D device removed callback LPDXUTCALLBACKFRAMEMOVE m_FrameMoveFunc; // frame move callback LPDXUTCALLBACKKEYBOARD m_KeyboardFunc; // keyboard callback LPDXUTCALLBACKMOUSE m_MouseFunc; // mouse callback LPDXUTCALLBACKMSGPROC m_WindowMsgFunc; // window messages callback LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE m_IsD3D11DeviceAcceptableFunc; // D3D11 is device acceptable callback LPDXUTCALLBACKD3D11DEVICECREATED m_D3D11DeviceCreatedFunc; // D3D11 device created callback LPDXUTCALLBACKD3D11SWAPCHAINRESIZED m_D3D11SwapChainResizedFunc; // D3D11 SwapChain reset callback LPDXUTCALLBACKD3D11SWAPCHAINRELEASING m_D3D11SwapChainReleasingFunc; // D3D11 SwapChain lost callback LPDXUTCALLBACKD3D11DEVICEDESTROYED m_D3D11DeviceDestroyedFunc; // D3D11 device destroyed callback LPDXUTCALLBACKD3D11FRAMERENDER m_D3D11FrameRenderFunc; // D3D11 frame render callback void* m_ModifyDeviceSettingsFuncUserContext; // user context for modify Direct3D device settings callback void* m_DeviceRemovedFuncUserContext; // user context for Direct3D device removed callback void* m_FrameMoveFuncUserContext; // user context for frame move callback void* m_KeyboardFuncUserContext; // user context for keyboard callback void* m_MouseFuncUserContext; // user context for mouse callback void* m_WindowMsgFuncUserContext; // user context for window messages callback void* m_IsD3D11DeviceAcceptableFuncUserContext; // user context for is D3D11 device acceptable callback void* m_D3D11DeviceCreatedFuncUserContext; // user context for D3D11 device created callback void* m_D3D11SwapChainResizedFuncUserContext; // user context for D3D11 SwapChain resized callback void* m_D3D11SwapChainReleasingFuncUserContext; // user context for D3D11 SwapChain releasing callback void* m_D3D11DeviceDestroyedFuncUserContext; // user context for D3D11 device destroyed callback void* m_D3D11FrameRenderFuncUserContext; // user context for D3D11 frame render callback bool m_Keys[256]; // array of key state bool m_LastKeys[256]; // array of last key state bool m_MouseButtons[5]; // array of mouse states std::vector* m_TimerList; // list of DXUT_TIMER structs WCHAR m_StaticFrameStats[256]; // static part of frames stats WCHAR m_FPSStats[64]; // fps stats WCHAR m_FrameStats[256]; // frame stats (fps, width, etc) WCHAR m_DeviceStats[256]; // device stats (description, device type, etc) WCHAR m_WindowTitle[256]; // window title }; STATE m_state; public: DXUTState() { Create(); } ~DXUTState() { Destroy(); } void Create() { g_bThreadSafe = true; (void)InitializeCriticalSectionAndSpinCount( &g_cs, 1000 ); ZeroMemory( &m_state, sizeof( STATE ) ); m_state.m_OverrideStartX = -1; m_state.m_OverrideStartY = -1; m_state.m_OverrideForceFeatureLevel = (D3D_FEATURE_LEVEL)0; m_state.m_ScreenShotName[0] = 0; m_state.m_SaveScreenShot = false; m_state.m_ExitAfterScreenShot = false; m_state.m_OverrideAdapterOrdinal = -1; m_state.m_OverrideOutput = -1; m_state.m_OverrideForceVsync = -1; m_state.m_AutoChangeAdapter = true; m_state.m_ShowMsgBoxOnError = true; m_state.m_AllowShortcutKeysWhenWindowed = true; m_state.m_Active = true; m_state.m_CallDefWindowProc = true; m_state.m_HandleEscape = true; m_state.m_HandleAltEnter = true; m_state.m_HandlePause = true; m_state.m_IsInGammaCorrectMode = true; m_state.m_FPS = 1.0f; m_state.m_MessageWhenD3D11NotAvailable = true; } void Destroy() { SAFE_DELETE( m_state.m_TimerList ); DXUTShutdown(); DeleteCriticalSection( &g_cs ); } // Macros to define access functions for thread safe access into m_state GET_SET_ACCESSOR( DXUTDeviceSettings*, CurrentDeviceSettings ); // D3D11 specific GET_SET_ACCESSOR( IDXGIFactory1*, DXGIFactory ); GET_SET_ACCESSOR( IDXGIAdapter1*, DXGIAdapter ); GET_SET_ACCESSOR( IDXGIOutput**, DXGIOutputArray ); GET_SET_ACCESSOR( UINT, DXGIOutputArraySize ); GET_SET_ACCESSOR( IDXGISwapChain*, DXGISwapChain ); GETP_SETP_ACCESSOR( DXGI_SURFACE_DESC, BackBufferSurfaceDescDXGI ); GET_SET_ACCESSOR( bool, RenderingOccluded ); GET_SET_ACCESSOR( bool, DoNotStoreBufferSize ); GET_SET_ACCESSOR( ID3D11Device*, D3D11Device ); GET_SET_ACCESSOR( ID3D11DeviceContext*, D3D11DeviceContext ); GET_SET_ACCESSOR( D3D_FEATURE_LEVEL, D3D11FeatureLevel ); GET_SET_ACCESSOR( ID3D11Texture2D*, D3D11DepthStencil ); GET_SET_ACCESSOR( ID3D11DepthStencilView*, D3D11DepthStencilView ); GET_SET_ACCESSOR( ID3D11RenderTargetView*, D3D11RenderTargetView ); GET_SET_ACCESSOR( ID3D11RasterizerState*, D3D11RasterizerState ); GET_SET_ACCESSOR( ID3D11Device1*, D3D11Device1 ); GET_SET_ACCESSOR( ID3D11DeviceContext1*, D3D11DeviceContext1 ); #ifdef USE_DIRECT3D11_2 GET_SET_ACCESSOR(ID3D11Device2*, D3D11Device2); GET_SET_ACCESSOR(ID3D11DeviceContext2*, D3D11DeviceContext2); #endif #ifdef USE_DIRECT3D11_3 GET_SET_ACCESSOR(ID3D11Device3*, D3D11Device3); GET_SET_ACCESSOR(ID3D11DeviceContext3*, D3D11DeviceContext3); #endif GET_SET_ACCESSOR( HWND, HWNDFocus ); GET_SET_ACCESSOR( HWND, HWNDDeviceFullScreen ); GET_SET_ACCESSOR( HWND, HWNDDeviceWindowed ); GET_SET_ACCESSOR( HMONITOR, AdapterMonitor ); GET_SET_ACCESSOR( HMENU, Menu ); GET_SET_ACCESSOR( UINT, FullScreenBackBufferWidthAtModeChange ); GET_SET_ACCESSOR( UINT, FullScreenBackBufferHeightAtModeChange ); GET_SET_ACCESSOR( UINT, WindowBackBufferWidthAtModeChange ); GET_SET_ACCESSOR( UINT, WindowBackBufferHeightAtModeChange ); GETP_SETP_ACCESSOR( WINDOWPLACEMENT, WindowedPlacement ); GET_SET_ACCESSOR( DWORD, WindowedStyleAtModeChange ); GET_SET_ACCESSOR( bool, TopmostWhileWindowed ); GET_SET_ACCESSOR( bool, Minimized ); GET_SET_ACCESSOR( bool, Maximized ); GET_SET_ACCESSOR( bool, MinimizedWhileFullscreen ); GET_SET_ACCESSOR( bool, IgnoreSizeChange ); GET_SET_ACCESSOR( double, Time ); GET_SET_ACCESSOR( double, AbsoluteTime ); GET_SET_ACCESSOR( float, ElapsedTime ); GET_SET_ACCESSOR( HINSTANCE, HInstance ); GET_SET_ACCESSOR( double, LastStatsUpdateTime ); GET_SET_ACCESSOR( DWORD, LastStatsUpdateFrames ); GET_SET_ACCESSOR( float, FPS ); GET_SET_ACCESSOR( int, CurrentFrameNumber ); GET_SET_ACCESSOR( HHOOK, KeyboardHook ); GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenFullscreen ); GET_SET_ACCESSOR( bool, AllowShortcutKeysWhenWindowed ); GET_SET_ACCESSOR( bool, AllowShortcutKeys ); GET_SET_ACCESSOR( bool, CallDefWindowProc ); GET_SET_ACCESSOR( STICKYKEYS, StartupStickyKeys ); GET_SET_ACCESSOR( TOGGLEKEYS, StartupToggleKeys ); GET_SET_ACCESSOR( FILTERKEYS, StartupFilterKeys ); GET_SET_ACCESSOR( bool, HandleEscape ); GET_SET_ACCESSOR( bool, HandleAltEnter ); GET_SET_ACCESSOR( bool, HandlePause ); GET_SET_ACCESSOR( bool, ShowMsgBoxOnError ); GET_SET_ACCESSOR( bool, NoStats ); GET_SET_ACCESSOR( bool, ClipCursorWhenFullScreen ); GET_SET_ACCESSOR( bool, ShowCursorWhenFullScreen ); GET_SET_ACCESSOR( bool, ConstantFrameTime ); GET_SET_ACCESSOR( float, TimePerFrame ); GET_SET_ACCESSOR( bool, WireframeMode ); GET_SET_ACCESSOR( bool, AutoChangeAdapter ); GET_SET_ACCESSOR( bool, WindowCreatedWithDefaultPositions ); GET_SET_ACCESSOR( int, ExitCode ); GET_SET_ACCESSOR( bool, DXUTInited ); GET_SET_ACCESSOR( bool, WindowCreated ); GET_SET_ACCESSOR( bool, DeviceCreated ); GET_SET_ACCESSOR( bool, DXUTInitCalled ); GET_SET_ACCESSOR( bool, WindowCreateCalled ); GET_SET_ACCESSOR( bool, DeviceCreateCalled ); GET_SET_ACCESSOR( bool, InsideDeviceCallback ); GET_SET_ACCESSOR( bool, InsideMainloop ); GET_SET_ACCESSOR( bool, DeviceObjectsCreated ); GET_SET_ACCESSOR( bool, DeviceObjectsReset ); GET_SET_ACCESSOR( bool, Active ); GET_SET_ACCESSOR( bool, RenderingPaused ); GET_SET_ACCESSOR( bool, TimePaused ); GET_SET_ACCESSOR( int, PauseRenderingCount ); GET_SET_ACCESSOR( int, PauseTimeCount ); GET_SET_ACCESSOR( bool, DeviceLost ); GET_SET_ACCESSOR( bool, NotifyOnMouseMove ); GET_SET_ACCESSOR( bool, Automation ); GET_SET_ACCESSOR( bool, InSizeMove ); GET_SET_ACCESSOR( UINT, TimerLastID ); GET_SET_ACCESSOR( bool, MessageWhenD3D11NotAvailable ); GET_SET_ACCESSOR( bool, AppCalledWasKeyPressed ); GET_SET_ACCESSOR( D3D_FEATURE_LEVEL, OverrideForceFeatureLevel ); GET_ACCESSOR( WCHAR*, ScreenShotName ); GET_SET_ACCESSOR( bool, SaveScreenShot ); GET_SET_ACCESSOR( bool, ExitAfterScreenShot ); GET_SET_ACCESSOR( int, OverrideAdapterOrdinal ); GET_SET_ACCESSOR( bool, OverrideWindowed ); GET_SET_ACCESSOR( int, OverrideOutput ); GET_SET_ACCESSOR( bool, OverrideFullScreen ); GET_SET_ACCESSOR( int, OverrideStartX ); GET_SET_ACCESSOR( int, OverrideStartY ); GET_SET_ACCESSOR( int, OverrideWidth ); GET_SET_ACCESSOR( int, OverrideHeight ); GET_SET_ACCESSOR( bool, OverrideForceHAL ); GET_SET_ACCESSOR( bool, OverrideForceREF ); GET_SET_ACCESSOR( bool, OverrideForceWARP ); GET_SET_ACCESSOR( bool, OverrideConstantFrameTime ); GET_SET_ACCESSOR( float, OverrideConstantTimePerFrame ); GET_SET_ACCESSOR( int, OverrideQuitAfterFrame ); GET_SET_ACCESSOR( int, OverrideForceVsync ); GET_SET_ACCESSOR( bool, ReleasingSwapChain ); GET_SET_ACCESSOR( bool, IsInGammaCorrectMode ); GET_SET_ACCESSOR( LPDXUTCALLBACKMODIFYDEVICESETTINGS, ModifyDeviceSettingsFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKDEVICEREMOVED, DeviceRemovedFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKFRAMEMOVE, FrameMoveFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKKEYBOARD, KeyboardFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKMOUSE, MouseFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKMSGPROC, WindowMsgFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE, IsD3D11DeviceAcceptableFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKD3D11DEVICECREATED, D3D11DeviceCreatedFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKD3D11SWAPCHAINRESIZED, D3D11SwapChainResizedFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKD3D11SWAPCHAINRELEASING, D3D11SwapChainReleasingFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKD3D11DEVICEDESTROYED, D3D11DeviceDestroyedFunc ); GET_SET_ACCESSOR( LPDXUTCALLBACKD3D11FRAMERENDER, D3D11FrameRenderFunc ); GET_SET_ACCESSOR( void*, ModifyDeviceSettingsFuncUserContext ); GET_SET_ACCESSOR( void*, DeviceRemovedFuncUserContext ); GET_SET_ACCESSOR( void*, FrameMoveFuncUserContext ); GET_SET_ACCESSOR( void*, KeyboardFuncUserContext ); GET_SET_ACCESSOR( void*, MouseFuncUserContext ); GET_SET_ACCESSOR( void*, WindowMsgFuncUserContext ); GET_SET_ACCESSOR( void*, IsD3D11DeviceAcceptableFuncUserContext ); GET_SET_ACCESSOR( void*, D3D11DeviceCreatedFuncUserContext ); GET_SET_ACCESSOR( void*, D3D11DeviceDestroyedFuncUserContext ); GET_SET_ACCESSOR( void*, D3D11SwapChainResizedFuncUserContext ); GET_SET_ACCESSOR( void*, D3D11SwapChainReleasingFuncUserContext ); GET_SET_ACCESSOR( void*, D3D11FrameRenderFuncUserContext ); GET_SET_ACCESSOR( std::vector*, TimerList ); GET_ACCESSOR( bool*, Keys ); GET_ACCESSOR( bool*, LastKeys ); GET_ACCESSOR( bool*, MouseButtons ); GET_ACCESSOR( WCHAR*, StaticFrameStats ); GET_ACCESSOR( WCHAR*, FPSStats ); GET_ACCESSOR( WCHAR*, FrameStats ); GET_ACCESSOR( WCHAR*, DeviceStats ); GET_ACCESSOR( WCHAR*, WindowTitle ); }; //-------------------------------------------------------------------------------------- // Global state //-------------------------------------------------------------------------------------- DXUTState* g_pDXUTState = nullptr; HRESULT WINAPI DXUTCreateState() { if( !g_pDXUTState ) { g_pDXUTState = new (std::nothrow) DXUTState; if( !g_pDXUTState ) return E_OUTOFMEMORY; } return S_OK; } void WINAPI DXUTDestroyState() { SAFE_DELETE( g_pDXUTState ); } class DXUTMemoryHelper { public: DXUTMemoryHelper() { DXUTCreateState(); } ~DXUTMemoryHelper() { DXUTDestroyState(); } }; DXUTState& GetDXUTState() { // This class will auto create the memory when its first accessed and delete it after the program exits WinMain. // However the application can also call DXUTCreateState() & DXUTDestroyState() independantly if its wants static DXUTMemoryHelper memory; assert( g_pDXUTState ); _Analysis_assume_( g_pDXUTState ); return *g_pDXUTState; } //-------------------------------------------------------------------------------------- // Internal functions forward declarations //-------------------------------------------------------------------------------------- void DXUTParseCommandLine( _In_z_ WCHAR* strCommandLine, _In_ bool bIgnoreFirstCommand = true ); bool DXUTIsNextArg( _Inout_ WCHAR*& strCmdLine, _In_ const WCHAR* strArg ); bool DXUTGetCmdParam( _Inout_ WCHAR*& strCmdLine, _Out_cap_(cchDest) WCHAR* strFlag, _In_ int cchDest ); void DXUTAllowShortcutKeys( _In_ bool bAllowKeys ); void DXUTUpdateStaticFrameStats(); void DXUTUpdateFrameStats(); LRESULT CALLBACK DXUTStaticWndProc( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ); void DXUTHandleTimers(); void DXUTDisplayErrorMessage( _In_ HRESULT hr ); int DXUTMapButtonToArrayIndex( _In_ BYTE vButton ); HRESULT DXUTChangeDevice( _In_ DXUTDeviceSettings* pNewDeviceSettings, _In_ bool bClipWindowToSingleAdapter ); bool DXUTCanDeviceBeReset( _In_ DXUTDeviceSettings* pOldDeviceSettings, _In_ DXUTDeviceSettings* pNewDeviceSettings, _In_ ID3D11Device* pd3d11DeviceFromApp ); HRESULT DXUTDelayLoadDXGI(); HRESULT DXUTSnapDeviceSettingsToEnumDevice( _In_ DXUTDeviceSettings* pDeviceSettings, _In_ bool forceEnum, _In_ D3D_FEATURE_LEVEL forceFL = D3D_FEATURE_LEVEL(0) ); void DXUTUpdateDeviceSettingsWithOverrides( _Inout_ DXUTDeviceSettings* pDeviceSettings ); void DXUTCheckForDXGIFullScreenSwitch(); void DXUTResizeDXGIBuffers( _In_ UINT Width, _In_ UINT Height, _In_ BOOL bFullscreen ); void DXUTCheckForDXGIBufferChange(); void DXUTCheckForWindowSizeChange(); void DXUTCheckForWindowChangingMonitors(); void DXUTCleanup3DEnvironment( _In_ bool bReleaseSettings ); HMONITOR DXUTGetMonitorFromAdapter( _In_ DXUTDeviceSettings* pDeviceSettings ); HRESULT DXUTGetAdapterOrdinalFromMonitor( _In_ HMONITOR hMonitor, _Out_ UINT* pAdapterOrdinal ); HRESULT DXUTGetOutputOrdinalFromMonitor( _In_ HMONITOR hMonitor, _Out_ UINT* pOutputOrdinal ); HRESULT DXUTHandleDeviceRemoved(); void DXUTUpdateBackBufferDesc(); void DXUTSetupCursor(); // Direct3D 11 HRESULT DXUTCreateD3D11Views( _In_ ID3D11Device* pd3dDevice, _In_ ID3D11DeviceContext* pd3dDeviceContext, _In_ DXUTDeviceSettings* pDeviceSettings ); HRESULT DXUTCreate3DEnvironment11(); HRESULT DXUTReset3DEnvironment11(); void DXUTUpdateD3D11DeviceStats( _In_ D3D_DRIVER_TYPE DeviceType, _In_ D3D_FEATURE_LEVEL featureLevel, _In_ DXGI_ADAPTER_DESC* pAdapterDesc ); //-------------------------------------------------------------------------------------- // Internal helper functions //-------------------------------------------------------------------------------------- UINT DXUTGetBackBufferWidthFromDS( _In_ DXUTDeviceSettings* pNewDeviceSettings ) { return pNewDeviceSettings->d3d11.sd.BufferDesc.Width; } UINT DXUTGetBackBufferHeightFromDS( _In_ DXUTDeviceSettings* pNewDeviceSettings ) { return pNewDeviceSettings->d3d11.sd.BufferDesc.Height; } bool DXUTGetIsWindowedFromDS( _In_ DXUTDeviceSettings* pNewDeviceSettings ) { if (!pNewDeviceSettings) return true; return pNewDeviceSettings->d3d11.sd.Windowed ? true : false; } //-------------------------------------------------------------------------------------- // External state access functions //-------------------------------------------------------------------------------------- bool WINAPI DXUTGetMSAASwapChainCreated() { DXUTDeviceSettings *psettings = GetDXUTState().GetCurrentDeviceSettings(); if ( !psettings ) return false; return (psettings->d3d11.sd.SampleDesc.Count > 1); } D3D_FEATURE_LEVEL WINAPI DXUTGetD3D11DeviceFeatureLevel() { return GetDXUTState().GetD3D11FeatureLevel(); } IDXGISwapChain* WINAPI DXUTGetDXGISwapChain() { return GetDXUTState().GetDXGISwapChain(); } ID3D11RenderTargetView* WINAPI DXUTGetD3D11RenderTargetView() { return GetDXUTState().GetD3D11RenderTargetView(); } ID3D11DepthStencilView* WINAPI DXUTGetD3D11DepthStencilView() { return GetDXUTState().GetD3D11DepthStencilView(); } const DXGI_SURFACE_DESC* WINAPI DXUTGetDXGIBackBufferSurfaceDesc() { return GetDXUTState().GetBackBufferSurfaceDescDXGI(); } HINSTANCE WINAPI DXUTGetHINSTANCE() { return GetDXUTState().GetHInstance(); } HWND WINAPI DXUTGetHWND() { return DXUTIsWindowed() ? GetDXUTState().GetHWNDDeviceWindowed() : GetDXUTState().GetHWNDDeviceFullScreen(); } HWND WINAPI DXUTGetHWNDFocus() { return GetDXUTState().GetHWNDFocus(); } HWND WINAPI DXUTGetHWNDDeviceFullScreen() { return GetDXUTState().GetHWNDDeviceFullScreen(); } HWND WINAPI DXUTGetHWNDDeviceWindowed() { return GetDXUTState().GetHWNDDeviceWindowed(); } RECT WINAPI DXUTGetWindowClientRect() { RECT rc; GetClientRect( DXUTGetHWND(), &rc ); return rc; } LONG WINAPI DXUTGetWindowWidth() { RECT rc = DXUTGetWindowClientRect(); return ((LONG)rc.right - rc.left); } LONG WINAPI DXUTGetWindowHeight() { RECT rc = DXUTGetWindowClientRect(); return ((LONG)rc.bottom - rc.top); } RECT WINAPI DXUTGetWindowClientRectAtModeChange() { RECT rc = { 0, 0, static_cast( GetDXUTState().GetWindowBackBufferWidthAtModeChange() ), static_cast( GetDXUTState().GetWindowBackBufferHeightAtModeChange() ) }; return rc; } RECT WINAPI DXUTGetFullsceenClientRectAtModeChange() { RECT rc = { 0, 0, static_cast( GetDXUTState().GetFullScreenBackBufferWidthAtModeChange() ), static_cast( GetDXUTState().GetFullScreenBackBufferHeightAtModeChange() ) }; return rc; } double WINAPI DXUTGetTime() { return GetDXUTState().GetTime(); } float WINAPI DXUTGetElapsedTime() { return GetDXUTState().GetElapsedTime(); } float WINAPI DXUTGetFPS() { return GetDXUTState().GetFPS(); } LPCWSTR WINAPI DXUTGetWindowTitle() { return GetDXUTState().GetWindowTitle(); } LPCWSTR WINAPI DXUTGetDeviceStats() { return GetDXUTState().GetDeviceStats(); } bool WINAPI DXUTIsRenderingPaused() { return GetDXUTState().GetPauseRenderingCount() > 0; } bool WINAPI DXUTIsTimePaused() { return GetDXUTState().GetPauseTimeCount() > 0; } bool WINAPI DXUTIsActive() { return GetDXUTState().GetActive(); } int WINAPI DXUTGetExitCode() { return GetDXUTState().GetExitCode(); } bool WINAPI DXUTGetShowMsgBoxOnError() { return GetDXUTState().GetShowMsgBoxOnError(); } bool WINAPI DXUTGetAutomation() { return GetDXUTState().GetAutomation(); } bool WINAPI DXUTIsWindowed() { return DXUTGetIsWindowedFromDS( GetDXUTState().GetCurrentDeviceSettings() ); } bool WINAPI DXUTIsInGammaCorrectMode() { return GetDXUTState().GetIsInGammaCorrectMode(); } IDXGIFactory1* WINAPI DXUTGetDXGIFactory() { DXUTDelayLoadDXGI(); return GetDXUTState().GetDXGIFactory(); } ID3D11Device* WINAPI DXUTGetD3D11Device() { return GetDXUTState().GetD3D11Device(); } ID3D11DeviceContext* WINAPI DXUTGetD3D11DeviceContext() { return GetDXUTState().GetD3D11DeviceContext(); } ID3D11Device1* WINAPI DXUTGetD3D11Device1() { return GetDXUTState().GetD3D11Device1(); } ID3D11DeviceContext1* WINAPI DXUTGetD3D11DeviceContext1() { return GetDXUTState().GetD3D11DeviceContext1(); } #ifdef USE_DIRECT3D11_2 ID3D11Device2* WINAPI DXUTGetD3D11Device2() { return GetDXUTState().GetD3D11Device2(); } ID3D11DeviceContext2* WINAPI DXUTGetD3D11DeviceContext2() { return GetDXUTState().GetD3D11DeviceContext2(); } #endif #ifdef USE_DIRECT3D11_3 ID3D11Device3* WINAPI DXUTGetD3D11Device3() { return GetDXUTState().GetD3D11Device3(); } ID3D11DeviceContext3* WINAPI DXUTGetD3D11DeviceContext3() { return GetDXUTState().GetD3D11DeviceContext3(); } #endif //-------------------------------------------------------------------------------------- // External callback setup functions //-------------------------------------------------------------------------------------- // General callbacks void WINAPI DXUTSetCallbackDeviceChanging( _In_ LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetModifyDeviceSettingsFunc( pCallback ); GetDXUTState().SetModifyDeviceSettingsFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackDeviceRemoved( _In_ LPDXUTCALLBACKDEVICEREMOVED pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetDeviceRemovedFunc( pCallback ); GetDXUTState().SetDeviceRemovedFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackFrameMove( _In_ LPDXUTCALLBACKFRAMEMOVE pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetFrameMoveFunc( pCallback ); GetDXUTState().SetFrameMoveFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackKeyboard( _In_ LPDXUTCALLBACKKEYBOARD pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetKeyboardFunc( pCallback ); GetDXUTState().SetKeyboardFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackMouse( _In_ LPDXUTCALLBACKMOUSE pCallback, bool bIncludeMouseMove, _In_opt_ void* pUserContext ) { GetDXUTState().SetMouseFunc( pCallback ); GetDXUTState().SetNotifyOnMouseMove( bIncludeMouseMove ); GetDXUTState().SetMouseFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackMsgProc( _In_ LPDXUTCALLBACKMSGPROC pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetWindowMsgFunc( pCallback ); GetDXUTState().SetWindowMsgFuncUserContext( pUserContext ); } // Direct3D 11 callbacks void WINAPI DXUTSetCallbackD3D11DeviceAcceptable( _In_ LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetIsD3D11DeviceAcceptableFunc( pCallback ); GetDXUTState().SetIsD3D11DeviceAcceptableFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackD3D11DeviceCreated( _In_ LPDXUTCALLBACKD3D11DEVICECREATED pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetD3D11DeviceCreatedFunc( pCallback ); GetDXUTState().SetD3D11DeviceCreatedFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackD3D11SwapChainResized( _In_ LPDXUTCALLBACKD3D11SWAPCHAINRESIZED pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetD3D11SwapChainResizedFunc( pCallback ); GetDXUTState().SetD3D11SwapChainResizedFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackD3D11FrameRender( _In_ LPDXUTCALLBACKD3D11FRAMERENDER pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetD3D11FrameRenderFunc( pCallback ); GetDXUTState().SetD3D11FrameRenderFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackD3D11SwapChainReleasing( _In_ LPDXUTCALLBACKD3D11SWAPCHAINRELEASING pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetD3D11SwapChainReleasingFunc( pCallback ); GetDXUTState().SetD3D11SwapChainReleasingFuncUserContext( pUserContext ); } void WINAPI DXUTSetCallbackD3D11DeviceDestroyed( _In_ LPDXUTCALLBACKD3D11DEVICEDESTROYED pCallback, _In_opt_ void* pUserContext ) { GetDXUTState().SetD3D11DeviceDestroyedFunc( pCallback ); GetDXUTState().SetD3D11DeviceDestroyedFuncUserContext( pUserContext ); } void DXUTGetCallbackD3D11DeviceAcceptable( _In_ LPDXUTCALLBACKISD3D11DEVICEACCEPTABLE* ppCallback, _Outptr_ void** ppUserContext ) { *ppCallback = GetDXUTState().GetIsD3D11DeviceAcceptableFunc(); *ppUserContext = GetDXUTState().GetIsD3D11DeviceAcceptableFuncUserContext(); } //-------------------------------------------------------------------------------------- // Optionally parses the command line and sets if default hotkeys are handled // // Possible command line parameters are: // -forcefeaturelevel:fl forces app to use a specified direct3D11 feature level // -screenshotexit:filename save a screenshot to the filename.bmp and exit. // -adapter:# forces app to use this adapter # (fails if the adapter doesn't exist) // -output:# forces app to use a particular output on the adapter (fails if the output doesn't exist) // -windowed forces app to start windowed // -fullscreen forces app to start full screen // -forcehal forces app to use HAL (fails if HAL doesn't exist) // -forceref forces app to use REF (fails if REF doesn't exist) // -forcewarp forces app to use WARP (fails if WARP doesn't exist) // -forcevsync:# if # is 0, then vsync is disabled // -width:# forces app to use # for width. for full screen, it will pick the closest possible supported mode // -height:# forces app to use # for height. for full screen, it will pick the closest possible supported mode // -startx:# forces app to use # for the x coord of the window position for windowed mode // -starty:# forces app to use # for the y coord of the window position for windowed mode // -constantframetime:# forces app to use constant frame time, where # is the time/frame in seconds // -quitafterframe:x forces app to quit after # frames // -noerrormsgboxes prevents the display of message boxes generated by the framework so the application can be run without user interaction // -nostats prevents the display of the stats // -automation a hint to other components that automation is active //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT WINAPI DXUTInit( bool bParseCommandLine, bool bShowMsgBoxOnError, WCHAR* strExtraCommandLineParams, bool bThreadSafeDXUT ) { g_bThreadSafe = bThreadSafeDXUT; HRESULT hr = CoInitializeEx( nullptr, COINIT_MULTITHREADED ); if ( FAILED(hr) ) return hr; GetDXUTState().SetDXUTInitCalled( true ); // Not always needed, but lets the app create GDI dialogs InitCommonControls(); // Save the current sticky/toggle/filter key settings so DXUT can restore them later STICKYKEYS sk = {sizeof(STICKYKEYS), 0}; if ( !SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &sk, 0) ) memset( &sk, 0, sizeof(sk) ); GetDXUTState().SetStartupStickyKeys( sk ); TOGGLEKEYS tk = {sizeof(TOGGLEKEYS), 0}; if ( !SystemParametersInfo(SPI_GETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tk, 0) ) memset( &tk, 0, sizeof(tk) ); GetDXUTState().SetStartupToggleKeys( tk ); FILTERKEYS fk = {sizeof(FILTERKEYS), 0}; if ( !SystemParametersInfo(SPI_GETFILTERKEYS, sizeof(FILTERKEYS), &fk, 0) ) memset( &fk, 0, sizeof(fk) ); GetDXUTState().SetStartupFilterKeys( fk ); GetDXUTState().SetShowMsgBoxOnError( bShowMsgBoxOnError ); if( bParseCommandLine ) DXUTParseCommandLine( GetCommandLine() ); if( strExtraCommandLineParams ) DXUTParseCommandLine( strExtraCommandLineParams, false ); // Reset the timer DXUTGetGlobalTimer()->Reset(); GetDXUTState().SetDXUTInited( true ); return S_OK; } //-------------------------------------------------------------------------------------- // Parses the command line for parameters. See DXUTInit() for list //-------------------------------------------------------------------------------------- _Use_decl_annotations_ void DXUTParseCommandLine(WCHAR* strCommandLine, bool bIgnoreFirstCommand ) { WCHAR* strCmdLine; WCHAR strFlag[MAX_PATH]; int nNumArgs; auto pstrArgList = CommandLineToArgvW( strCommandLine, &nNumArgs ); int iArgStart = 0; if( bIgnoreFirstCommand ) iArgStart = 1; for( int iArg = iArgStart; iArg < nNumArgs; iArg++ ) { strCmdLine = pstrArgList[iArg]; // Handle flag args if( *strCmdLine == L'/' || *strCmdLine == L'-' ) { strCmdLine++; if( DXUTIsNextArg( strCmdLine, L"forcefeaturelevel" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { #ifdef USE_DIRECT3D11_3 if (_wcsnicmp(strFlag, L"D3D_FEATURE_LEVEL_12_1", MAX_PATH) == 0) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_12_1); } else if (_wcsnicmp(strFlag, L"D3D_FEATURE_LEVEL_12_0", MAX_PATH) == 0) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_12_0); } else #endif if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_11_1", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_11_1); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_11_0", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_11_0); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_10_1", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_10_1); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_10_0", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_10_0); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_9_3", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_9_3); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_9_2", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_9_2); }else if (_wcsnicmp( strFlag, L"D3D_FEATURE_LEVEL_9_1", MAX_PATH) == 0 ) { GetDXUTState().SetOverrideForceFeatureLevel(D3D_FEATURE_LEVEL_9_1); } continue; } } if( DXUTIsNextArg( strCmdLine, L"adapter" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nAdapter = _wtoi( strFlag ); GetDXUTState().SetOverrideAdapterOrdinal( nAdapter ); continue; } } if( DXUTIsNextArg( strCmdLine, L"windowed" ) ) { GetDXUTState().SetOverrideWindowed( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"output" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int Output = _wtoi( strFlag ); GetDXUTState().SetOverrideOutput( Output ); continue; } } if( DXUTIsNextArg( strCmdLine, L"fullscreen" ) ) { GetDXUTState().SetOverrideFullScreen( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"forcehal" ) ) { GetDXUTState().SetOverrideForceHAL( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"screenshotexit" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { GetDXUTState().SetExitAfterScreenShot( true ); GetDXUTState().SetSaveScreenShot( true ); swprintf_s( GetDXUTState().GetScreenShotName(), 256, L"%ls.bmp", strFlag ); continue; } } if( DXUTIsNextArg( strCmdLine, L"forceref" ) ) { GetDXUTState().SetOverrideForceREF( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"forcewarp" ) ) { GetDXUTState().SetOverrideForceWARP( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"forcevsync" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nOn = _wtoi( strFlag ); GetDXUTState().SetOverrideForceVsync( nOn ); continue; } } if( DXUTIsNextArg( strCmdLine, L"width" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nWidth = _wtoi( strFlag ); GetDXUTState().SetOverrideWidth( nWidth ); continue; } } if( DXUTIsNextArg( strCmdLine, L"height" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nHeight = _wtoi( strFlag ); GetDXUTState().SetOverrideHeight( nHeight ); continue; } } if( DXUTIsNextArg( strCmdLine, L"startx" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nX = _wtoi( strFlag ); GetDXUTState().SetOverrideStartX( nX ); continue; } } if( DXUTIsNextArg( strCmdLine, L"starty" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nY = _wtoi( strFlag ); GetDXUTState().SetOverrideStartY( nY ); continue; } } if( DXUTIsNextArg( strCmdLine, L"constantframetime" ) ) { float fTimePerFrame; if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) fTimePerFrame = ( float )wcstod( strFlag, nullptr ); else fTimePerFrame = 0.0333f; GetDXUTState().SetOverrideConstantFrameTime( true ); GetDXUTState().SetOverrideConstantTimePerFrame( fTimePerFrame ); DXUTSetConstantFrameTime( true, fTimePerFrame ); continue; } if( DXUTIsNextArg( strCmdLine, L"quitafterframe" ) ) { if( DXUTGetCmdParam( strCmdLine, strFlag, MAX_PATH ) ) { int nFrame = _wtoi( strFlag ); GetDXUTState().SetOverrideQuitAfterFrame( nFrame ); continue; } } if( DXUTIsNextArg( strCmdLine, L"noerrormsgboxes" ) ) { GetDXUTState().SetShowMsgBoxOnError( false ); continue; } if( DXUTIsNextArg( strCmdLine, L"nostats" ) ) { GetDXUTState().SetNoStats( true ); continue; } if( DXUTIsNextArg( strCmdLine, L"automation" ) ) { GetDXUTState().SetAutomation( true ); continue; } } // Unrecognized flag wcscpy_s( strFlag, MAX_PATH, strCmdLine ); WCHAR* strSpace = strFlag; while( *strSpace && ( *strSpace > L' ' ) ) strSpace++; *strSpace = 0; DXUTOutputDebugString( L"Unrecognized flag: %ls", strFlag ); strCmdLine += wcslen( strFlag ); } LocalFree( pstrArgList ); } //-------------------------------------------------------------------------------------- // Helper function for DXUTParseCommandLine //-------------------------------------------------------------------------------------- _Use_decl_annotations_ bool DXUTIsNextArg( WCHAR*& strCmdLine, const WCHAR* strArg ) { size_t nArgLen = wcslen( strArg ); size_t nCmdLen = wcslen( strCmdLine ); if( nCmdLen >= nArgLen && _wcsnicmp( strCmdLine, strArg, nArgLen ) == 0 && ( strCmdLine[nArgLen] == 0 || strCmdLine[nArgLen] == L':' ) ) { strCmdLine += nArgLen; return true; } return false; } //-------------------------------------------------------------------------------------- // Helper function for DXUTParseCommandLine. Updates strCmdLine and strFlag // Example: if strCmdLine=="-width:1024 -forceref" // then after: strCmdLine==" -forceref" and strFlag=="1024" //-------------------------------------------------------------------------------------- _Use_decl_annotations_ bool DXUTGetCmdParam( WCHAR*& strCmdLine, WCHAR* strFlag, int cchDest ) { if( *strCmdLine == L':' ) { strCmdLine++; // Skip ':' // Place nul terminator in strFlag after current token wcscpy_s( strFlag, cchDest, strCmdLine ); WCHAR* strSpace = strFlag; int count = 0; while( *strSpace && ( *strSpace > L' ' ) && (count < cchDest) ) { ++strSpace; ++count; } *strSpace = 0; // Update strCmdLine strCmdLine += wcslen( strFlag ); return true; } else { strFlag[0] = 0; return false; } } //-------------------------------------------------------------------------------------- // Creates a window with the specified window title, icon, menu, and // starting position. If DXUTInit() has not already been called, it will // call it with the default parameters. Instead of calling this, you can // call DXUTSetWindow() to use an existing window. //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT WINAPI DXUTCreateWindow( const WCHAR* strWindowTitle, HINSTANCE hInstance, HICON hIcon, HMENU hMenu, int x, int y ) { HRESULT hr; // Not allowed to call this from inside the device callbacks if( GetDXUTState().GetInsideDeviceCallback() ) return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL ); GetDXUTState().SetWindowCreateCalled( true ); if( !GetDXUTState().GetDXUTInited() ) { // If DXUTInit() was already called and failed, then fail. // DXUTInit() must first succeed for this function to succeed if( GetDXUTState().GetDXUTInitCalled() ) return E_FAIL; // If DXUTInit() hasn't been called, then automatically call it // with default params hr = DXUTInit(); if( FAILED( hr ) ) return hr; } if( !DXUTGetHWNDFocus() ) { if( !hInstance ) hInstance = ( HINSTANCE )GetModuleHandle( nullptr ); GetDXUTState().SetHInstance( hInstance ); WCHAR szExePath[MAX_PATH]; GetModuleFileName( nullptr, szExePath, MAX_PATH ); if( !hIcon ) // If the icon is NULL, then use the first one found in the exe hIcon = ExtractIcon( hInstance, szExePath, 0 ); // Register the windows class WNDCLASS wndClass; wndClass.style = CS_DBLCLKS; wndClass.lpfnWndProc = DXUTStaticWndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = hIcon; wndClass.hCursor = LoadCursor( nullptr, IDC_ARROW ); wndClass.hbrBackground = ( HBRUSH )GetStockObject( BLACK_BRUSH ); wndClass.lpszMenuName = nullptr; wndClass.lpszClassName = L"Direct3DWindowClass"; if( !RegisterClass( &wndClass ) ) { DWORD dwError = GetLastError(); if( dwError != ERROR_CLASS_ALREADY_EXISTS ) return DXUT_ERR_MSGBOX( L"RegisterClass", HRESULT_FROM_WIN32(dwError) ); } // Override the window's initial & size position if there were cmd line args if( GetDXUTState().GetOverrideStartX() != -1 ) x = GetDXUTState().GetOverrideStartX(); if( GetDXUTState().GetOverrideStartY() != -1 ) y = GetDXUTState().GetOverrideStartY(); GetDXUTState().SetWindowCreatedWithDefaultPositions( false ); if( x == CW_USEDEFAULT && y == CW_USEDEFAULT ) GetDXUTState().SetWindowCreatedWithDefaultPositions( true ); // Find the window's initial size, but it might be changed later int nDefaultWidth = 800; int nDefaultHeight = 600; if( GetDXUTState().GetOverrideWidth() != 0 ) nDefaultWidth = GetDXUTState().GetOverrideWidth(); if( GetDXUTState().GetOverrideHeight() != 0 ) nDefaultHeight = GetDXUTState().GetOverrideHeight(); RECT rc; SetRect( &rc, 0, 0, nDefaultWidth, nDefaultHeight ); AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, ( hMenu ) ? true : false ); WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle(); wcscpy_s( strCachedWindowTitle, 256, strWindowTitle ); // Create the render window HWND hWnd = CreateWindow( L"Direct3DWindowClass", strWindowTitle, WS_OVERLAPPEDWINDOW, x, y, ( rc.right - rc.left ), ( rc.bottom - rc.top ), 0, hMenu, hInstance, 0 ); if( !hWnd ) { DWORD dwError = GetLastError(); return DXUT_ERR_MSGBOX( L"CreateWindow", HRESULT_FROM_WIN32(dwError) ); } GetDXUTState().SetWindowCreated( true ); GetDXUTState().SetHWNDFocus( hWnd ); GetDXUTState().SetHWNDDeviceFullScreen( hWnd ); GetDXUTState().SetHWNDDeviceWindowed( hWnd ); } return S_OK; } //-------------------------------------------------------------------------------------- // Sets a previously created window for the framework to use. If DXUTInit() // has not already been called, it will call it with the default parameters. // Instead of calling this, you can call DXUTCreateWindow() to create a new window. //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT WINAPI DXUTSetWindow( HWND hWndFocus, HWND hWndDeviceFullScreen, HWND hWndDeviceWindowed, bool bHandleMessages ) { HRESULT hr; // Not allowed to call this from inside the device callbacks if( GetDXUTState().GetInsideDeviceCallback() ) return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL ); GetDXUTState().SetWindowCreateCalled( true ); // To avoid confusion, we do not allow any HWND to be nullptr here. The // caller must pass in valid HWND for all three parameters. The same // HWND may be used for more than one parameter. if( !hWndFocus || !hWndDeviceFullScreen || !hWndDeviceWindowed ) return DXUT_ERR_MSGBOX( L"DXUTSetWindow", E_INVALIDARG ); // If subclassing the window, set the pointer to the local window procedure if( bHandleMessages ) { // Switch window procedures LONG_PTR nResult = SetWindowLongPtr( hWndFocus, GWLP_WNDPROC, (LONG_PTR)DXUTStaticWndProc ); DWORD dwError = GetLastError(); if( nResult == 0 ) return DXUT_ERR_MSGBOX( L"SetWindowLongPtr", HRESULT_FROM_WIN32(dwError) ); } if( !GetDXUTState().GetDXUTInited() ) { // If DXUTInit() was already called and failed, then fail. // DXUTInit() must first succeed for this function to succeed if( GetDXUTState().GetDXUTInitCalled() ) return E_FAIL; // If DXUTInit() hasn't been called, then automatically call it // with default params hr = DXUTInit(); if( FAILED( hr ) ) return hr; } WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle(); GetWindowText( hWndFocus, strCachedWindowTitle, 255 ); strCachedWindowTitle[255] = 0; HINSTANCE hInstance = ( HINSTANCE )( LONG_PTR )GetWindowLongPtr( hWndFocus, GWLP_HINSTANCE ); GetDXUTState().SetHInstance( hInstance ); GetDXUTState().SetWindowCreatedWithDefaultPositions( false ); GetDXUTState().SetWindowCreated( true ); GetDXUTState().SetHWNDFocus( hWndFocus ); GetDXUTState().SetHWNDDeviceFullScreen( hWndDeviceFullScreen ); GetDXUTState().SetHWNDDeviceWindowed( hWndDeviceWindowed ); return S_OK; } //-------------------------------------------------------------------------------------- // Handles window messages //-------------------------------------------------------------------------------------- _Use_decl_annotations_ LRESULT CALLBACK DXUTStaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // Consolidate the keyboard messages and pass them to the app's keyboard callback if( uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP ) { bool bKeyDown = ( uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN ); DWORD dwMask = ( 1 << 29 ); bool bAltDown = ( ( lParam & dwMask ) != 0 ); bool* bKeys = GetDXUTState().GetKeys(); bKeys[ ( BYTE )( wParam & 0xFF ) ] = bKeyDown; LPDXUTCALLBACKKEYBOARD pCallbackKeyboard = GetDXUTState().GetKeyboardFunc(); if( pCallbackKeyboard ) pCallbackKeyboard( ( UINT )wParam, bKeyDown, bAltDown, GetDXUTState().GetKeyboardFuncUserContext() ); } // Consolidate the mouse button messages and pass them to the app's mouse callback if( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK || uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP || uMsg == WM_MBUTTONDBLCLK || uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP || uMsg == WM_RBUTTONDBLCLK || uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP || uMsg == WM_XBUTTONDBLCLK || uMsg == WM_MOUSEWHEEL || ( GetDXUTState().GetNotifyOnMouseMove() && uMsg == WM_MOUSEMOVE ) ) { int xPos = ( short )LOWORD( lParam ); int yPos = ( short )HIWORD( lParam ); if( uMsg == WM_MOUSEWHEEL ) { // WM_MOUSEWHEEL passes screen mouse coords // so convert them to client coords POINT pt; pt.x = xPos; pt.y = yPos; ScreenToClient( hWnd, &pt ); xPos = pt.x; yPos = pt.y; } int nMouseWheelDelta = 0; if( uMsg == WM_MOUSEWHEEL ) nMouseWheelDelta = ( short )HIWORD( wParam ); int nMouseButtonState = LOWORD( wParam ); bool bLeftButton = ( ( nMouseButtonState & MK_LBUTTON ) != 0 ); bool bRightButton = ( ( nMouseButtonState & MK_RBUTTON ) != 0 ); bool bMiddleButton = ( ( nMouseButtonState & MK_MBUTTON ) != 0 ); bool bSideButton1 = ( ( nMouseButtonState & MK_XBUTTON1 ) != 0 ); bool bSideButton2 = ( ( nMouseButtonState & MK_XBUTTON2 ) != 0 ); bool* bMouseButtons = GetDXUTState().GetMouseButtons(); bMouseButtons[0] = bLeftButton; bMouseButtons[1] = bMiddleButton; bMouseButtons[2] = bRightButton; bMouseButtons[3] = bSideButton1; bMouseButtons[4] = bSideButton2; LPDXUTCALLBACKMOUSE pCallbackMouse = GetDXUTState().GetMouseFunc(); if( pCallbackMouse ) pCallbackMouse( bLeftButton, bRightButton, bMiddleButton, bSideButton1, bSideButton2, nMouseWheelDelta, xPos, yPos, GetDXUTState().GetMouseFuncUserContext() ); } // TODO - WM_POINTER for touch when on Windows 8.0 // Pass all messages to the app's MsgProc callback, and don't // process further messages if the apps says not to. LPDXUTCALLBACKMSGPROC pCallbackMsgProc = GetDXUTState().GetWindowMsgFunc(); if( pCallbackMsgProc ) { bool bNoFurtherProcessing = false; LRESULT nResult = pCallbackMsgProc( hWnd, uMsg, wParam, lParam, &bNoFurtherProcessing, GetDXUTState().GetWindowMsgFuncUserContext() ); if( bNoFurtherProcessing ) return nResult; } switch( uMsg ) { case WM_PAINT: { // Handle paint messages when the app is paused if( DXUTIsRenderingPaused() && GetDXUTState().GetDeviceObjectsCreated() && GetDXUTState().GetDeviceObjectsReset() ) { HRESULT hr; double fTime = DXUTGetTime(); float fElapsedTime = DXUTGetElapsedTime(); { auto pd3dDevice = DXUTGetD3D11Device(); auto pDeferred = DXUTGetD3D11DeviceContext(); if( pd3dDevice ) { LPDXUTCALLBACKD3D11FRAMERENDER pCallbackFrameRender = GetDXUTState().GetD3D11FrameRenderFunc(); if( pCallbackFrameRender && !GetDXUTState().GetRenderingOccluded() ) { pCallbackFrameRender( pd3dDevice,pDeferred, fTime, fElapsedTime, GetDXUTState().GetD3D11FrameRenderFuncUserContext() ); } DWORD dwFlags = 0; if( GetDXUTState().GetRenderingOccluded() ) dwFlags = DXGI_PRESENT_TEST; else dwFlags = GetDXUTState().GetCurrentDeviceSettings()->d3d11.PresentFlags; auto pSwapChain = DXUTGetDXGISwapChain(); hr = pSwapChain->Present( 0, dwFlags ); if( DXGI_STATUS_OCCLUDED == hr ) { // There is a window covering our entire rendering area. // Don't render until we're visible again. GetDXUTState().SetRenderingOccluded( true ); } else if( SUCCEEDED( hr ) ) { if( GetDXUTState().GetRenderingOccluded() ) { // Now that we're no longer occluded // allow us to render again GetDXUTState().SetRenderingOccluded( false ); } } } } } break; } case WM_SIZE: if( SIZE_MINIMIZED == wParam ) { DXUTPause( true, true ); // Pause while we're minimized GetDXUTState().SetMinimized( true ); GetDXUTState().SetMaximized( false ); } else { RECT rcCurrentClient; GetClientRect( DXUTGetHWND(), &rcCurrentClient ); if( rcCurrentClient.top == 0 && rcCurrentClient.bottom == 0 ) { // Rapidly clicking the task bar to minimize and restore a window // can cause a WM_SIZE message with SIZE_RESTORED when // the window has actually become minimized due to rapid change // so just ignore this message } else if( SIZE_MAXIMIZED == wParam ) { if( GetDXUTState().GetMinimized() ) DXUTPause( false, false ); // Unpause since we're no longer minimized GetDXUTState().SetMinimized( false ); GetDXUTState().SetMaximized( true ); DXUTCheckForWindowSizeChange(); DXUTCheckForWindowChangingMonitors(); } else if( SIZE_RESTORED == wParam ) { //DXUTCheckForDXGIFullScreenSwitch(); if( GetDXUTState().GetMaximized() ) { GetDXUTState().SetMaximized( false ); DXUTCheckForWindowSizeChange(); DXUTCheckForWindowChangingMonitors(); } else if( GetDXUTState().GetMinimized() ) { DXUTPause( false, false ); // Unpause since we're no longer minimized GetDXUTState().SetMinimized( false ); DXUTCheckForWindowSizeChange(); DXUTCheckForWindowChangingMonitors(); } else if( GetDXUTState().GetInSizeMove() ) { // If we're neither maximized nor minimized, the window size // is changing by the user dragging the window edges. In this // case, we don't reset the device yet -- we wait until the // user stops dragging, and a WM_EXITSIZEMOVE message comes. } else { // This WM_SIZE come from resizing the window via an API like SetWindowPos() so // resize and reset the device now. DXUTCheckForWindowSizeChange(); DXUTCheckForWindowChangingMonitors(); } } } break; case WM_GETMINMAXINFO: ( ( MINMAXINFO* )lParam )->ptMinTrackSize.x = DXUT_MIN_WINDOW_SIZE_X; ( ( MINMAXINFO* )lParam )->ptMinTrackSize.y = DXUT_MIN_WINDOW_SIZE_Y; break; case WM_ENTERSIZEMOVE: // Halt frame movement while the app is sizing or moving DXUTPause( true, true ); GetDXUTState().SetInSizeMove( true ); break; case WM_EXITSIZEMOVE: DXUTPause( false, false ); DXUTCheckForWindowSizeChange(); DXUTCheckForWindowChangingMonitors(); GetDXUTState().SetInSizeMove( false ); break; case WM_SETCURSOR: if( DXUTIsActive() && !DXUTIsWindowed() ) { if( !GetDXUTState().GetShowCursorWhenFullScreen() ) SetCursor( nullptr ); return true; // prevent Windows from setting cursor to window class cursor } break; case WM_ACTIVATEAPP: if( wParam == TRUE && !DXUTIsActive() ) // Handle only if previously not active { GetDXUTState().SetActive( true ); // Enable controller rumble & input when activating app DXUTEnableXInput( true ); // The GetMinimizedWhileFullscreen() varible is used instead of !DXUTIsWindowed() // to handle the rare case toggling to windowed mode while the fullscreen application // is minimized and thus making the pause count wrong if( GetDXUTState().GetMinimizedWhileFullscreen() ) { GetDXUTState().SetMinimizedWhileFullscreen( false ); DXUTToggleFullScreen(); } // Upon returning to this app, potentially disable shortcut keys // (Windows key, accessibility shortcuts) DXUTAllowShortcutKeys( ( DXUTIsWindowed() ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() : GetDXUTState().GetAllowShortcutKeysWhenFullscreen() ); } else if( wParam == FALSE && DXUTIsActive() ) // Handle only if previously active { GetDXUTState().SetActive( false ); // Disable any controller rumble & input when de-activating app DXUTEnableXInput( false ); if( !DXUTIsWindowed() ) { // Going from full screen to a minimized state ClipCursor( nullptr ); // don't limit the cursor anymore GetDXUTState().SetMinimizedWhileFullscreen( true ); } // Restore shortcut keys (Windows key, accessibility shortcuts) to original state // // This is important to call here if the shortcuts are disabled, // because if this is not done then the Windows key will continue to // be disabled while this app is running which is very bad. // If the app crashes, the Windows key will return to normal. DXUTAllowShortcutKeys( true ); } break; case WM_ENTERMENULOOP: // Pause the app when menus are displayed DXUTPause( true, true ); break; case WM_EXITMENULOOP: DXUTPause( false, false ); break; case WM_MENUCHAR: // A menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key // So just ignore and don't beep return MAKELRESULT( 0, MNC_CLOSE ); break; case WM_NCHITTEST: // Prevent the user from selecting the menu in full screen mode if( !DXUTIsWindowed() ) return HTCLIENT; break; case WM_POWERBROADCAST: switch( wParam ) { case PBT_APMQUERYSUSPEND: // At this point, the app should save any data for open // network connections, files, etc., and prepare to go into // a suspended mode. The app can use the MsgProc callback // to handle this if desired. return true; case PBT_APMRESUMESUSPEND: // At this point, the app should recover any data, network // connections, files, etc., and resume running from when // the app was suspended. The app can use the MsgProc callback // to handle this if desired. // QPC may lose consistency when suspending, so reset the timer // upon resume. DXUTGetGlobalTimer()->Reset(); GetDXUTState().SetLastStatsUpdateTime( 0 ); return true; } break; case WM_SYSCOMMAND: // Prevent moving/sizing in full screen mode switch( ( wParam & 0xFFF0 ) ) { case SC_MOVE: case SC_SIZE: case SC_MAXIMIZE: case SC_KEYMENU: if( !DXUTIsWindowed() ) return 0; break; } break; case WM_KEYDOWN: { switch( wParam ) { case VK_ESCAPE: { if( GetDXUTState().GetHandleEscape() ) SendMessage( hWnd, WM_CLOSE, 0, 0 ); break; } case VK_PAUSE: { if( GetDXUTState().GetHandlePause() ) { bool bTimePaused = DXUTIsTimePaused(); bTimePaused = !bTimePaused; if( bTimePaused ) DXUTPause( true, false ); else DXUTPause( false, false ); } break; } } break; } case WM_CLOSE: { HMENU hMenu; hMenu = GetMenu( hWnd ); if( hMenu ) DestroyMenu( hMenu ); DestroyWindow( hWnd ); UnregisterClass( L"Direct3DWindowClass", nullptr ); GetDXUTState().SetHWNDFocus( nullptr ); GetDXUTState().SetHWNDDeviceFullScreen( nullptr ); GetDXUTState().SetHWNDDeviceWindowed( nullptr ); return 0; } case WM_DESTROY: PostQuitMessage( 0 ); break; } // Don't allow the F10 key to act as a shortcut to the menu bar // by not passing these messages to the DefWindowProc only when // there's no menu present if( !GetDXUTState().GetCallDefWindowProc() || !GetDXUTState().GetMenu() && ( uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP ) && wParam == VK_F10 ) return 0; else return DefWindowProc( hWnd, uMsg, wParam, lParam ); } //-------------------------------------------------------------------------------------- // Handles app's message loop and rendering when idle. If DXUTCreateDevice() // has not already been called, it will call DXUTCreateWindow() with the default parameters. //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTMainLoop( _In_opt_ HACCEL hAccel ) { HRESULT hr; // Not allowed to call this from inside the device callbacks or reenter if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL ); } GetDXUTState().SetInsideMainloop( true ); // If DXUTCreateDevice() has not already been called, // then call DXUTCreateDevice() with the default parameters. if( !GetDXUTState().GetDeviceCreated() ) { if( GetDXUTState().GetDeviceCreateCalled() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed } hr = DXUTCreateDevice(D3D_FEATURE_LEVEL_10_0, true, 800, 600); if( FAILED( hr ) ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return hr; } } HWND hWnd = DXUTGetHWND(); // DXUTInit() must have been called and succeeded for this function to proceed // DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed // DXUTCreateDevice() or DXUTCreateDeviceFromSettings() must have been called and succeeded for this function to proceed if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL ); } // Now we're ready to receive and process Windows messages. bool bGotMsg; MSG msg; msg.message = WM_NULL; PeekMessage( &msg, nullptr, 0U, 0U, PM_NOREMOVE ); while( WM_QUIT != msg.message ) { // Use PeekMessage() so we can use idle time to render the scene. bGotMsg = ( PeekMessage( &msg, nullptr, 0U, 0U, PM_REMOVE ) != 0 ); if( bGotMsg ) { // Translate and dispatch the message if( !hAccel || !hWnd || 0 == TranslateAccelerator( hWnd, hAccel, &msg ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } else { // Render a frame during idle time (no messages are waiting) DXUTRender3DEnvironment(); } } // Cleanup the accelerator table if( hAccel ) DestroyAcceleratorTable( hAccel ); GetDXUTState().SetInsideMainloop( false ); return S_OK; } //====================================================================================== //====================================================================================== // Direct3D section //====================================================================================== //====================================================================================== _Use_decl_annotations_ HRESULT WINAPI DXUTCreateDevice(D3D_FEATURE_LEVEL reqFL, bool bWindowed, int nSuggestedWidth, int nSuggestedHeight) { HRESULT hr = S_OK; // Not allowed to call this from inside the device callbacks if( GetDXUTState().GetInsideDeviceCallback() ) return DXUT_ERR_MSGBOX( L"DXUTCreateDevice", E_FAIL ); GetDXUTState().SetDeviceCreateCalled( true ); // If DXUTCreateWindow() or DXUTSetWindow() has not already been called, // then call DXUTCreateWindow() with the default parameters. if( !GetDXUTState().GetWindowCreated() ) { // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail. // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed if( GetDXUTState().GetWindowCreateCalled() ) return E_FAIL; // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then // automatically call DXUTCreateWindow() with default params hr = DXUTCreateWindow(); if( FAILED( hr ) ) return hr; } DXUTDeviceSettings deviceSettings; DXUTApplyDefaultDeviceSettings(&deviceSettings); deviceSettings.MinimumFeatureLevel = reqFL; deviceSettings.d3d11.sd.BufferDesc.Width = nSuggestedWidth; deviceSettings.d3d11.sd.BufferDesc.Height = nSuggestedHeight; deviceSettings.d3d11.sd.Windowed = bWindowed; DXUTUpdateDeviceSettingsWithOverrides(&deviceSettings); GetDXUTState().SetWindowBackBufferWidthAtModeChange(deviceSettings.d3d11.sd.BufferDesc.Width); GetDXUTState().SetWindowBackBufferHeightAtModeChange(deviceSettings.d3d11.sd.BufferDesc.Height); GetDXUTState().SetFullScreenBackBufferWidthAtModeChange(deviceSettings.d3d11.sd.BufferDesc.Width); GetDXUTState().SetFullScreenBackBufferHeightAtModeChange(deviceSettings.d3d11.sd.BufferDesc.Height); // Change to a Direct3D device created from the new device settings. // If there is an existing device, then either reset or recreated the scene hr = DXUTChangeDevice( &deviceSettings, true ); if ( hr == DXUTERR_NODIRECT3D && GetDXUTState().GetMessageWhenD3D11NotAvailable() ) { OSVERSIONINFOEX osv; memset( &osv, 0, sizeof(osv) ); osv.dwOSVersionInfoSize = sizeof(osv); #pragma warning( suppress : 4996 28159 ) GetVersionEx( (LPOSVERSIONINFO)&osv ); if ( ( osv.dwMajorVersion > 6 ) || ( osv.dwMajorVersion == 6 && osv.dwMinorVersion >= 1 ) || ( osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0 && osv.dwBuildNumber > 6002 ) ) { MessageBox( 0, L"Direct3D 11 components were not found.", L"Error", MB_ICONEXCLAMATION ); // This should not happen, but is here for completeness as the system could be // corrupted or some future OS version could pull D3D11.DLL for some reason } else if ( osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0 && osv.dwBuildNumber == 6002 ) { MessageBox( 0, L"Direct3D 11 components were not found, but are available for"\ L" this version of Windows.\n"\ L"For details see Microsoft Knowledge Base Article #971644\n"\ L"http://go.microsoft.com/fwlink/?LinkId=160189", L"Error", MB_ICONEXCLAMATION ); } else if ( osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0 ) { MessageBox( 0, L"Direct3D 11 components were not found. Please install the latest Service Pack.\n"\ L"For details see Microsoft Knowledge Base Article #935791\n"\ L"http://support.microsoft.com/kb/935791/", L"Error", MB_ICONEXCLAMATION ); } else { MessageBox( 0, L"Direct3D 11 is not supported on this OS.", L"Error", MB_ICONEXCLAMATION ); } } if( FAILED( hr ) ) return hr; return hr; } //-------------------------------------------------------------------------------------- // Tells the framework to change to a device created from the passed in device settings // If DXUTCreateWindow() has not already been called, it will call it with the // default parameters. Instead of calling this, you can call DXUTCreateDevice() //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT WINAPI DXUTCreateDeviceFromSettings( DXUTDeviceSettings* pDeviceSettings, bool bClipWindowToSingleAdapter ) { if ( !pDeviceSettings ) return E_INVALIDARG; HRESULT hr; GetDXUTState().SetDeviceCreateCalled( true ); // If DXUTCreateWindow() or DXUTSetWindow() has not already been called, // then call DXUTCreateWindow() with the default parameters. if( !GetDXUTState().GetWindowCreated() ) { // If DXUTCreateWindow() or DXUTSetWindow() was already called and failed, then fail. // DXUTCreateWindow() or DXUTSetWindow() must first succeed for this function to succeed if( GetDXUTState().GetWindowCreateCalled() ) return E_FAIL; // If DXUTCreateWindow() or DXUTSetWindow() hasn't been called, then // automatically call DXUTCreateWindow() with default params hr = DXUTCreateWindow(); if( FAILED( hr ) ) return hr; } DXUTUpdateDeviceSettingsWithOverrides(pDeviceSettings); GetDXUTState().SetWindowBackBufferWidthAtModeChange(pDeviceSettings->d3d11.sd.BufferDesc.Width); GetDXUTState().SetWindowBackBufferHeightAtModeChange(pDeviceSettings->d3d11.sd.BufferDesc.Height); GetDXUTState().SetFullScreenBackBufferWidthAtModeChange(pDeviceSettings->d3d11.sd.BufferDesc.Width); GetDXUTState().SetFullScreenBackBufferHeightAtModeChange(pDeviceSettings->d3d11.sd.BufferDesc.Height); // Change to a Direct3D device created from the new device settings. // If there is an existing device, then either reset or recreate the scene hr = DXUTChangeDevice( pDeviceSettings, bClipWindowToSingleAdapter ); if( FAILED( hr ) ) return hr; return S_OK; } //-------------------------------------------------------------------------------------- // All device changes are sent to this function. It looks at the current // device (if any) and the new device and determines the best course of action. It // also remembers and restores the window state if toggling between windowed and fullscreen // as well as sets the proper window and system state for switching to the new device. //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DXUTChangeDevice( DXUTDeviceSettings* pNewDeviceSettings, bool bClipWindowToSingleAdapter ) { if ( GetDXUTState().GetReleasingSwapChain() ) return S_FALSE; HRESULT hr = S_OK; DXUTDeviceSettings* pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); if( !pNewDeviceSettings ) return S_FALSE; hr = DXUTDelayLoadDXGI(); if( FAILED( hr ) ) return hr; // Make a copy of the pNewDeviceSettings on the heap DXUTDeviceSettings* pNewDeviceSettingsOnHeap = new (std::nothrow) DXUTDeviceSettings; if( !pNewDeviceSettingsOnHeap ) return E_OUTOFMEMORY; memcpy( pNewDeviceSettingsOnHeap, pNewDeviceSettings, sizeof( DXUTDeviceSettings ) ); pNewDeviceSettings = pNewDeviceSettingsOnHeap; GetDXUTState().SetCurrentDeviceSettings(pNewDeviceSettingsOnHeap); hr = DXUTSnapDeviceSettingsToEnumDevice(pNewDeviceSettingsOnHeap, false); if( FAILED( hr ) ) // the call will fail if no valid devices were found { DXUTDisplayErrorMessage( hr ); return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr ); } // If the ModifyDeviceSettings callback is non-NULL, then call it to let the app // change the settings or reject the device change by returning false. LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = GetDXUTState().GetModifyDeviceSettingsFunc(); if( pCallbackModifyDeviceSettings ) { bool bContinue = pCallbackModifyDeviceSettings( pNewDeviceSettings, GetDXUTState().GetModifyDeviceSettingsFuncUserContext() ); if( !bContinue ) { // The app rejected the device change by returning false, so just use the current device if there is one. if( !pOldDeviceSettings ) DXUTDisplayErrorMessage( DXUTERR_NOCOMPATIBLEDEVICES ); SAFE_DELETE( pNewDeviceSettings ); return E_ABORT; } if( !GetDXUTState().GetDXGIFactory() ) // if DXUTShutdown() was called in the modify callback, just return { SAFE_DELETE( pNewDeviceSettings ); return S_FALSE; } DXUTSnapDeviceSettingsToEnumDevice(pNewDeviceSettingsOnHeap, false); // modify the app specified settings to the closed enumerated settigns if( FAILED( hr ) ) // the call will fail if no valid devices were found { DXUTDisplayErrorMessage( hr ); return DXUT_ERR( L"DXUTFindValidDeviceSettings", hr ); } } GetDXUTState().SetCurrentDeviceSettings( pNewDeviceSettingsOnHeap ); DXUTPause( true, true ); // Take note if the backbuffer width & height are 0 now as they will change after pd3dDevice->Reset() bool bKeepCurrentWindowSize = false; if( DXUTGetBackBufferWidthFromDS( pNewDeviceSettings ) == 0 && DXUTGetBackBufferHeightFromDS( pNewDeviceSettings ) == 0 ) bKeepCurrentWindowSize = true; ////////////////////////// // Before reset ///////////////////////// if( DXUTGetIsWindowedFromDS( pNewDeviceSettings ) ) { // Going to windowed mode if( pOldDeviceSettings && !DXUTGetIsWindowedFromDS( pOldDeviceSettings ) ) { // Going from fullscreen -> windowed GetDXUTState().SetFullScreenBackBufferWidthAtModeChange( DXUTGetBackBufferWidthFromDS( pOldDeviceSettings ) ); GetDXUTState().SetFullScreenBackBufferHeightAtModeChange( DXUTGetBackBufferHeightFromDS( pOldDeviceSettings ) ); } } else { // Going to fullscreen mode if( !pOldDeviceSettings || ( pOldDeviceSettings && DXUTGetIsWindowedFromDS( pOldDeviceSettings ) ) ) { // Transistioning to full screen mode from a standard window so if( pOldDeviceSettings ) { GetDXUTState().SetWindowBackBufferWidthAtModeChange( DXUTGetBackBufferWidthFromDS( pOldDeviceSettings ) ); GetDXUTState().SetWindowBackBufferHeightAtModeChange( DXUTGetBackBufferHeightFromDS( pOldDeviceSettings ) ); } } } if( pOldDeviceSettings ) DXUTCleanup3DEnvironment( false ); // Create the D3D device and call the app's device callbacks hr = DXUTCreate3DEnvironment11(); if( FAILED( hr ) ) { SAFE_DELETE( pOldDeviceSettings ); DXUTCleanup3DEnvironment( true ); DXUTDisplayErrorMessage( hr ); DXUTPause( false, false ); GetDXUTState().SetIgnoreSizeChange( false ); return hr; } // Enable/disable StickKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut, and Windows key // to prevent accidental task switching DXUTAllowShortcutKeys( ( DXUTGetIsWindowedFromDS( pNewDeviceSettings ) ) ? GetDXUTState().GetAllowShortcutKeysWhenWindowed() : GetDXUTState().GetAllowShortcutKeysWhenFullscreen() ); HMONITOR hAdapterMonitor = DXUTGetMonitorFromAdapter( pNewDeviceSettings ); GetDXUTState().SetAdapterMonitor( hAdapterMonitor ); // Update the device stats text DXUTUpdateStaticFrameStats(); if( pOldDeviceSettings && !DXUTGetIsWindowedFromDS( pOldDeviceSettings ) && DXUTGetIsWindowedFromDS( pNewDeviceSettings ) ) { // Going from fullscreen -> windowed // Restore the show state, and positions/size of the window to what it was // It is important to adjust the window size // after resetting the device rather than beforehand to ensure // that the monitor resolution is correct and does not limit the size of the new window. auto pwp = GetDXUTState().GetWindowedPlacement(); SetWindowPlacement( DXUTGetHWNDDeviceWindowed(), pwp ); // Also restore the z-order of window to previous state HWND hWndInsertAfter = GetDXUTState().GetTopmostWhileWindowed() ? HWND_TOPMOST : HWND_NOTOPMOST; SetWindowPos( DXUTGetHWNDDeviceWindowed(), hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE ); } // Check to see if the window needs to be resized. // Handle cases where the window is minimized and maxmimized as well. bool bNeedToResize = false; if( DXUTGetIsWindowedFromDS( pNewDeviceSettings ) && // only resize if in windowed mode !bKeepCurrentWindowSize ) // only resize if pp.BackbufferWidth/Height were not 0 { UINT nClientWidth; UINT nClientHeight; if( IsIconic( DXUTGetHWNDDeviceWindowed() ) ) { // Window is currently minimized. To tell if it needs to resize, // get the client rect of window when its restored the // hard way using GetWindowPlacement() WINDOWPLACEMENT wp; ZeroMemory( &wp, sizeof( WINDOWPLACEMENT ) ); wp.length = sizeof( WINDOWPLACEMENT ); GetWindowPlacement( DXUTGetHWNDDeviceWindowed(), &wp ); if( ( wp.flags & WPF_RESTORETOMAXIMIZED ) != 0 && wp.showCmd == SW_SHOWMINIMIZED ) { // WPF_RESTORETOMAXIMIZED means that when the window is restored it will // be maximized. So maximize the window temporarily to get the client rect // when the window is maximized. GetSystemMetrics( SM_CXMAXIMIZED ) will give this // information if the window is on the primary but this will work on multimon. ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE ); RECT rcClient; GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient ); nClientWidth = ( UINT )( rcClient.right - rcClient.left ); nClientHeight = ( UINT )( rcClient.bottom - rcClient.top ); ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_MINIMIZE ); } else { // Use wp.rcNormalPosition to get the client rect, but wp.rcNormalPosition // includes the window frame so subtract it RECT rcFrame = {0}; AdjustWindowRect( &rcFrame, GetDXUTState().GetWindowedStyleAtModeChange(), GetDXUTState().GetMenu() != 0 ); LONG nFrameWidth = rcFrame.right - rcFrame.left; LONG nFrameHeight = rcFrame.bottom - rcFrame.top; nClientWidth = ( UINT )( wp.rcNormalPosition.right - wp.rcNormalPosition.left - nFrameWidth ); nClientHeight = ( UINT )( wp.rcNormalPosition.bottom - wp.rcNormalPosition.top - nFrameHeight ); } } else { // Window is restored or maximized so just get its client rect RECT rcClient; GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient ); nClientWidth = ( UINT )( rcClient.right - rcClient.left ); nClientHeight = ( UINT )( rcClient.bottom - rcClient.top ); } // Now that we know the client rect, compare it against the back buffer size // to see if the client rect is already the right size if( nClientWidth != DXUTGetBackBufferWidthFromDS( pNewDeviceSettings ) || nClientHeight != DXUTGetBackBufferHeightFromDS( pNewDeviceSettings ) ) { bNeedToResize = true; } if( bClipWindowToSingleAdapter && !IsIconic( DXUTGetHWNDDeviceWindowed() ) ) { // Get the rect of the monitor attached to the adapter MONITORINFO miAdapter; miAdapter.cbSize = sizeof( MONITORINFO ); hAdapterMonitor = DXUTGetMonitorFromAdapter( pNewDeviceSettings ); DXUTGetMonitorInfo( hAdapterMonitor, &miAdapter ); HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY ); // Get the rect of the window RECT rcWindow; GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow ); // Check if the window rect is fully inside the adapter's vitural screen rect if( ( rcWindow.left < miAdapter.rcWork.left || rcWindow.right > miAdapter.rcWork.right || rcWindow.top < miAdapter.rcWork.top || rcWindow.bottom > miAdapter.rcWork.bottom ) ) { if( hWindowMonitor == hAdapterMonitor && IsZoomed( DXUTGetHWNDDeviceWindowed() ) ) { // If the window is maximized and on the same monitor as the adapter, then // no need to clip to single adapter as the window is already clipped // even though the rcWindow rect is outside of the miAdapter.rcWork } else { bNeedToResize = true; } } } } // Only resize window if needed if( bNeedToResize ) { // Need to resize, so if window is maximized or minimized then restore the window if( IsIconic( DXUTGetHWNDDeviceWindowed() ) ) ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE ); if( IsZoomed( DXUTGetHWNDDeviceWindowed() ) ) // doing the IsIconic() check first also handles the WPF_RESTORETOMAXIMIZED case ShowWindow( DXUTGetHWNDDeviceWindowed(), SW_RESTORE ); if( bClipWindowToSingleAdapter ) { // Get the rect of the monitor attached to the adapter MONITORINFO miAdapter; miAdapter.cbSize = sizeof( MONITORINFO ); hAdapterMonitor = DXUTGetMonitorFromAdapter( pNewDeviceSettings ); DXUTGetMonitorInfo( hAdapterMonitor, &miAdapter ); // Get the rect of the monitor attached to the window MONITORINFO miWindow; miWindow.cbSize = sizeof( MONITORINFO ); DXUTGetMonitorInfo( DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY ), &miWindow ); // Do something reasonable if the BackBuffer size is greater than the monitor size int nAdapterMonitorWidth = miAdapter.rcWork.right - miAdapter.rcWork.left; int nAdapterMonitorHeight = miAdapter.rcWork.bottom - miAdapter.rcWork.top; int nClientWidth = DXUTGetBackBufferWidthFromDS( pNewDeviceSettings ); int nClientHeight = DXUTGetBackBufferHeightFromDS( pNewDeviceSettings ); // Get the rect of the window RECT rcWindow; GetWindowRect( DXUTGetHWNDDeviceWindowed(), &rcWindow ); // Make a window rect with a client rect that is the same size as the backbuffer RECT rcResizedWindow; rcResizedWindow.left = 0; rcResizedWindow.right = nClientWidth; rcResizedWindow.top = 0; rcResizedWindow.bottom = nClientHeight; AdjustWindowRect( &rcResizedWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != 0 ); int nWindowWidth = rcResizedWindow.right - rcResizedWindow.left; int nWindowHeight = rcResizedWindow.bottom - rcResizedWindow.top; if( nWindowWidth > nAdapterMonitorWidth ) nWindowWidth = nAdapterMonitorWidth; if( nWindowHeight > nAdapterMonitorHeight ) nWindowHeight = nAdapterMonitorHeight; if( rcResizedWindow.left < miAdapter.rcWork.left || rcResizedWindow.top < miAdapter.rcWork.top || rcResizedWindow.right > miAdapter.rcWork.right || rcResizedWindow.bottom > miAdapter.rcWork.bottom ) { int nWindowOffsetX = ( nAdapterMonitorWidth - nWindowWidth ) / 2; int nWindowOffsetY = ( nAdapterMonitorHeight - nWindowHeight ) / 2; rcResizedWindow.left = miAdapter.rcWork.left + nWindowOffsetX; rcResizedWindow.top = miAdapter.rcWork.top + nWindowOffsetY; rcResizedWindow.right = miAdapter.rcWork.left + nWindowOffsetX + nWindowWidth; rcResizedWindow.bottom = miAdapter.rcWork.top + nWindowOffsetY + nWindowHeight; } // Resize the window. It is important to adjust the window size // after resetting the device rather than beforehand to ensure // that the monitor resolution is correct and does not limit the size of the new window. SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, rcResizedWindow.left, rcResizedWindow.top, nWindowWidth, nWindowHeight, SWP_NOZORDER ); } else { // Make a window rect with a client rect that is the same size as the backbuffer RECT rcWindow = {0}; rcWindow.right = (long)( DXUTGetBackBufferWidthFromDS(pNewDeviceSettings) ); rcWindow.bottom = (long)( DXUTGetBackBufferHeightFromDS(pNewDeviceSettings) ); AdjustWindowRect( &rcWindow, GetWindowLong( DXUTGetHWNDDeviceWindowed(), GWL_STYLE ), GetDXUTState().GetMenu() != 0 ); // Resize the window. It is important to adjust the window size // after resetting the device rather than beforehand to ensure // that the monitor resolution is correct and does not limit the size of the new window. int cx = ( int )( rcWindow.right - rcWindow.left ); int cy = ( int )( rcWindow.bottom - rcWindow.top ); SetWindowPos( DXUTGetHWNDDeviceWindowed(), 0, 0, 0, cx, cy, SWP_NOZORDER | SWP_NOMOVE ); } // Its possible that the new window size is not what we asked for. // No window can be sized larger than the desktop, so see if the Windows OS resized the // window to something smaller to fit on the desktop. Also if WM_GETMINMAXINFO // will put a limit on the smallest/largest window size. RECT rcClient; GetClientRect( DXUTGetHWNDDeviceWindowed(), &rcClient ); UINT nClientWidth = ( UINT )( rcClient.right - rcClient.left ); UINT nClientHeight = ( UINT )( rcClient.bottom - rcClient.top ); if( nClientWidth != DXUTGetBackBufferWidthFromDS( pNewDeviceSettings ) || nClientHeight != DXUTGetBackBufferHeightFromDS( pNewDeviceSettings ) ) { // If its different, then resize the backbuffer again. This time create a backbuffer that matches the // client rect of the current window w/o resizing the window. auto deviceSettings = DXUTGetDeviceSettings(); deviceSettings.d3d11.sd.BufferDesc.Width = 0; deviceSettings.d3d11.sd.BufferDesc.Height = 0; hr = DXUTChangeDevice( &deviceSettings, bClipWindowToSingleAdapter ); if( FAILED( hr ) ) { SAFE_DELETE( pOldDeviceSettings ); DXUTCleanup3DEnvironment( true ); DXUTPause( false, false ); GetDXUTState().SetIgnoreSizeChange( false ); return hr; } } } //if (DXUTGetIsWindowedFromDS( pNewDeviceSettings )) { // RECT rcFrame = {0}; // AdjustWindowRect( &rcFrame, GetDXUTState().GetWindowedStyleAtModeChange(), GetDXUTState().GetMenu() ); // } // Make the window visible if( !IsWindowVisible( DXUTGetHWND() ) ) ShowWindow( DXUTGetHWND(), SW_SHOW ); // Ensure that the display doesn't power down when fullscreen but does when windowed if( !DXUTIsWindowed() ) SetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS ); else SetThreadExecutionState( ES_CONTINUOUS ); SAFE_DELETE( pOldDeviceSettings ); GetDXUTState().SetIgnoreSizeChange( false ); DXUTPause( false, false ); GetDXUTState().SetDeviceCreated( true ); return S_OK; } //-------------------------------------------------------------------------------------- // Creates a DXGI factory object if one has not already been created //-------------------------------------------------------------------------------------- HRESULT DXUTDelayLoadDXGI() { auto pDXGIFactory = GetDXUTState().GetDXGIFactory(); if( !pDXGIFactory ) { HRESULT hr = DXUT_Dynamic_CreateDXGIFactory1( IID_PPV_ARGS(&pDXGIFactory) ); if ( FAILED(hr) ) return hr; GetDXUTState().SetDXGIFactory( pDXGIFactory ); if( !pDXGIFactory ) { return DXUTERR_NODIRECT3D; } // DXGI 1.1 implies Direct3D 11 } return S_OK; } //-------------------------------------------------------------------------------------- // Updates the device settings with default values.. //-------------------------------------------------------------------------------------- void DXUTUpdateDeviceSettingsWithOverrides( _Inout_ DXUTDeviceSettings* pDeviceSettings ) { // Override with settings from the command line if( GetDXUTState().GetOverrideWidth() != 0 ) { pDeviceSettings->d3d11.sd.BufferDesc.Width = GetDXUTState().GetOverrideWidth(); } if( GetDXUTState().GetOverrideHeight() != 0 ) { pDeviceSettings->d3d11.sd.BufferDesc.Height = GetDXUTState().GetOverrideHeight(); } if( GetDXUTState().GetOverrideAdapterOrdinal() != -1 ) { pDeviceSettings->d3d11.AdapterOrdinal = GetDXUTState().GetOverrideAdapterOrdinal(); } if( GetDXUTState().GetOverrideFullScreen() ) { pDeviceSettings->d3d11.sd.Windowed = FALSE; } if( GetDXUTState().GetOverrideWindowed() ) { pDeviceSettings->d3d11.sd.Windowed = TRUE; } if( GetDXUTState().GetOverrideForceHAL() ) { pDeviceSettings->d3d11.DriverType = D3D_DRIVER_TYPE_HARDWARE; } if( GetDXUTState().GetOverrideForceREF() ) { pDeviceSettings->d3d11.DriverType = D3D_DRIVER_TYPE_REFERENCE; } if( GetDXUTState().GetOverrideForceWARP() ) { pDeviceSettings->d3d11.DriverType = D3D_DRIVER_TYPE_WARP; pDeviceSettings->d3d11.sd.Windowed = TRUE; } if( GetDXUTState().GetOverrideForceVsync() == 0 ) { pDeviceSettings->d3d11.SyncInterval = 0; } else if( GetDXUTState().GetOverrideForceVsync() == 1 ) { pDeviceSettings->d3d11.SyncInterval = 1; } if (GetDXUTState().GetOverrideForceFeatureLevel() != 0) { pDeviceSettings->d3d11.DeviceFeatureLevel = GetDXUTState().GetOverrideForceFeatureLevel(); } } //-------------------------------------------------------------------------------------- // Sets the viewport, render target view, and depth stencil view. //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTSetupD3D11Views( _In_ ID3D11DeviceContext* pd3dDeviceContext ) { HRESULT hr = S_OK; // Setup the viewport to match the backbuffer D3D11_VIEWPORT vp; vp.Width = (FLOAT)DXUTGetDXGIBackBufferSurfaceDesc()->Width; vp.Height = (FLOAT)DXUTGetDXGIBackBufferSurfaceDesc()->Height; vp.MinDepth = 0; vp.MaxDepth = 1; vp.TopLeftX = 0; vp.TopLeftY = 0; pd3dDeviceContext->RSSetViewports( 1, &vp ); // Set the render targets auto pRTV = GetDXUTState().GetD3D11RenderTargetView(); auto pDSV = GetDXUTState().GetD3D11DepthStencilView(); pd3dDeviceContext->OMSetRenderTargets( 1, &pRTV, pDSV ); return hr; } //-------------------------------------------------------------------------------------- // Creates a render target view, and depth stencil texture and view. //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DXUTCreateD3D11Views( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, DXUTDeviceSettings* pDeviceSettings ) { HRESULT hr = S_OK; auto pSwapChain = DXUTGetDXGISwapChain(); ID3D11DepthStencilView* pDSV = nullptr; ID3D11RenderTargetView* pRTV = nullptr; // Get the back buffer and desc ID3D11Texture2D* pBackBuffer; hr = pSwapChain->GetBuffer( 0, IID_PPV_ARGS(&pBackBuffer) ); if( FAILED( hr ) ) return hr; D3D11_TEXTURE2D_DESC backBufferSurfaceDesc; pBackBuffer->GetDesc( &backBufferSurfaceDesc ); // Create the render target view hr = pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &pRTV ); SAFE_RELEASE( pBackBuffer ); if( FAILED( hr ) ) return hr; DXUT_SetDebugName( pRTV, "DXUT" ); GetDXUTState().SetD3D11RenderTargetView( pRTV ); if( pDeviceSettings->d3d11.AutoCreateDepthStencil ) { // Create depth stencil texture ID3D11Texture2D* pDepthStencil = nullptr; D3D11_TEXTURE2D_DESC descDepth; descDepth.Width = backBufferSurfaceDesc.Width; descDepth.Height = backBufferSurfaceDesc.Height; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = pDeviceSettings->d3d11.AutoDepthStencilFormat; descDepth.SampleDesc.Count = pDeviceSettings->d3d11.sd.SampleDesc.Count; descDepth.SampleDesc.Quality = pDeviceSettings->d3d11.sd.SampleDesc.Quality; descDepth.Usage = D3D11_USAGE_DEFAULT; descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; descDepth.CPUAccessFlags = 0; descDepth.MiscFlags = 0; hr = pd3dDevice->CreateTexture2D( &descDepth, nullptr, &pDepthStencil ); if( FAILED( hr ) ) return hr; DXUT_SetDebugName( pDepthStencil, "DXUT" ); GetDXUTState().SetD3D11DepthStencil( pDepthStencil ); // Create the depth stencil view D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; descDSV.Format = descDepth.Format; descDSV.Flags = 0; if( descDepth.SampleDesc.Count > 1 ) descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; else descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, &descDSV, &pDSV ); if( FAILED( hr ) ) return hr; DXUT_SetDebugName( pDSV, "DXUT" ); GetDXUTState().SetD3D11DepthStencilView( pDSV ); } hr = DXUTSetupD3D11Views( pd3dImmediateContext ); if( FAILED( hr ) ) return hr; return hr; } //-------------------------------------------------------------------------------------- // Creates the 3D environment //-------------------------------------------------------------------------------------- HRESULT DXUTCreate3DEnvironment11() { HRESULT hr = S_OK; ID3D11Device* pd3d11Device = nullptr; ID3D11DeviceContext* pd3dImmediateContext = nullptr; D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_1; IDXGISwapChain* pSwapChain = nullptr; auto pNewDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); assert( pNewDeviceSettings ); _Analysis_assume_( pNewDeviceSettings ); auto pDXGIFactory = DXUTGetDXGIFactory(); assert( pDXGIFactory ); _Analysis_assume_( pDXGIFactory ); hr = pDXGIFactory->MakeWindowAssociation( DXUTGetHWND(), 0 ); // Try to create the device with the chosen settings IDXGIAdapter1* pAdapter = nullptr; hr = S_OK; D3D_DRIVER_TYPE ddt = pNewDeviceSettings->d3d11.DriverType; if( pNewDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_HARDWARE ) { hr = pDXGIFactory->EnumAdapters1( pNewDeviceSettings->d3d11.AdapterOrdinal, &pAdapter ); if ( FAILED( hr) ) { return E_FAIL; } ddt = D3D_DRIVER_TYPE_UNKNOWN; } else if (pNewDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_WARP) { ddt = D3D_DRIVER_TYPE_WARP; pAdapter = nullptr; } else if (pNewDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE) { ddt = D3D_DRIVER_TYPE_REFERENCE; pAdapter = nullptr; } if( SUCCEEDED( hr ) ) { hr = DXUT_Dynamic_D3D11CreateDevice( pAdapter, ddt, ( HMODULE )0, pNewDeviceSettings->d3d11.CreateFlags, &pNewDeviceSettings->d3d11.DeviceFeatureLevel, 1, D3D11_SDK_VERSION, &pd3d11Device, &FeatureLevel, &pd3dImmediateContext ); if ( FAILED( hr ) ) { pAdapter = nullptr; // Remote desktop does not allow you to enumerate the adapter. In this case, we let D3D11 do the enumeration. if ( ddt == D3D_DRIVER_TYPE_UNKNOWN ) { hr = DXUT_Dynamic_D3D11CreateDevice( pAdapter, D3D_DRIVER_TYPE_HARDWARE, ( HMODULE )0, pNewDeviceSettings->d3d11.CreateFlags, &pNewDeviceSettings->d3d11.DeviceFeatureLevel, 1, D3D11_SDK_VERSION, &pd3d11Device, &FeatureLevel, &pd3dImmediateContext ); } if ( FAILED ( hr ) ) { DXUT_ERR( L"D3D11CreateDevice", hr ); return DXUTERR_CREATINGDEVICE; } } } #ifndef NDEBUG if( SUCCEEDED( hr ) ) { ID3D11Debug * d3dDebug = nullptr; if( SUCCEEDED( pd3d11Device->QueryInterface(IID_PPV_ARGS(&d3dDebug) ) ) ) { ID3D11InfoQueue* infoQueue = nullptr; if( SUCCEEDED( d3dDebug->QueryInterface( IID_PPV_ARGS(&infoQueue) ) ) ) { // ignore some "expected" errors D3D11_MESSAGE_ID denied [] = { D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS, }; D3D11_INFO_QUEUE_FILTER filter; memset( &filter, 0, sizeof(filter) ); filter.DenyList.NumIDs = _countof(denied); filter.DenyList.pIDList = denied; infoQueue->AddStorageFilterEntries( &filter ); infoQueue->Release(); } d3dDebug->Release(); } } #endif if( SUCCEEDED( hr ) ) { IDXGIDevice1* pDXGIDev = nullptr; hr = pd3d11Device->QueryInterface( IID_PPV_ARGS(&pDXGIDev) ); if( SUCCEEDED( hr ) && pDXGIDev ) { if ( !pAdapter ) { IDXGIAdapter *pTempAdapter = nullptr; V_RETURN( pDXGIDev->GetAdapter( &pTempAdapter ) ); V_RETURN( pTempAdapter->QueryInterface( IID_PPV_ARGS(&pAdapter) ) ); V_RETURN( pAdapter->GetParent( IID_PPV_ARGS(&pDXGIFactory) ) ); SAFE_RELEASE ( pTempAdapter ); if ( GetDXUTState().GetDXGIFactory() != pDXGIFactory ) GetDXUTState().GetDXGIFactory()->Release(); GetDXUTState().SetDXGIFactory( pDXGIFactory ); } } SAFE_RELEASE( pDXGIDev ); GetDXUTState().SetDXGIAdapter( pAdapter ); } if( FAILED( hr ) ) { DXUT_ERR( L"D3D11CreateDevice", hr ); return DXUTERR_CREATINGDEVICE; } // set default render state to msaa enabled D3D11_RASTERIZER_DESC drd = { D3D11_FILL_SOLID, //D3D11_FILL_MODE FillMode; D3D11_CULL_BACK,//D3D11_CULL_MODE CullMode; FALSE, //BOOL FrontCounterClockwise; 0, //INT DepthBias; 0.0f,//FLOAT DepthBiasClamp; 0.0f,//FLOAT SlopeScaledDepthBias; TRUE,//BOOL DepthClipEnable; FALSE,//BOOL ScissorEnable; TRUE,//BOOL MultisampleEnable; FALSE//BOOL AntialiasedLineEnable; }; ID3D11RasterizerState* pRS = nullptr; hr = pd3d11Device->CreateRasterizerState(&drd, &pRS); if ( FAILED( hr ) ) { DXUT_ERR( L"CreateRasterizerState", hr ); return DXUTERR_CREATINGDEVICE; } DXUT_SetDebugName( pRS, "DXUT Default" ); GetDXUTState().SetD3D11RasterizerState(pRS); pd3dImmediateContext->RSSetState(pRS); // Enumerate its outputs. UINT OutputCount, iOutput; for( OutputCount = 0; ; ++OutputCount ) { IDXGIOutput* pOutput; if( FAILED( pAdapter->EnumOutputs( OutputCount, &pOutput ) ) ) break; SAFE_RELEASE( pOutput ); } auto ppOutputArray = new (std::nothrow) IDXGIOutput*[OutputCount]; if( !ppOutputArray ) return E_OUTOFMEMORY; for( iOutput = 0; iOutput < OutputCount; ++iOutput ) pAdapter->EnumOutputs( iOutput, ppOutputArray + iOutput ); GetDXUTState().SetDXGIOutputArray( ppOutputArray ); GetDXUTState().SetDXGIOutputArraySize( OutputCount ); // Create the swapchain hr = pDXGIFactory->CreateSwapChain( pd3d11Device, &pNewDeviceSettings->d3d11.sd, &pSwapChain ); if( FAILED( hr ) ) { DXUT_ERR( L"CreateSwapChain", hr ); return DXUTERR_CREATINGDEVICE; } GetDXUTState().SetD3D11Device( pd3d11Device ); GetDXUTState().SetD3D11DeviceContext( pd3dImmediateContext ); GetDXUTState().SetD3D11FeatureLevel( FeatureLevel ); GetDXUTState().SetDXGISwapChain( pSwapChain ); assert( pd3d11Device ); _Analysis_assume_( pd3d11Device ); assert( pd3dImmediateContext ); _Analysis_assume_( pd3dImmediateContext ); // Direct3D 11.1 { ID3D11Device1* pd3d11Device1 = nullptr; hr = pd3d11Device->QueryInterface(IID_PPV_ARGS(&pd3d11Device1)); if( SUCCEEDED( hr ) && pd3d11Device1 ) { GetDXUTState().SetD3D11Device1( pd3d11Device1 ); ID3D11DeviceContext1* pd3dImmediateContext1 = nullptr; hr = pd3dImmediateContext->QueryInterface(IID_PPV_ARGS(&pd3dImmediateContext1)); if( SUCCEEDED( hr ) && pd3dImmediateContext1 ) { GetDXUTState().SetD3D11DeviceContext1( pd3dImmediateContext1 ); } } } #ifdef USE_DIRECT3D11_2 // Direct3D 11.2 { ID3D11Device2* pd3d11Device2 = nullptr; hr = pd3d11Device->QueryInterface(IID_PPV_ARGS(&pd3d11Device2)); if (SUCCEEDED(hr) && pd3d11Device2) { GetDXUTState().SetD3D11Device2(pd3d11Device2); ID3D11DeviceContext2* pd3dImmediateContext2 = nullptr; hr = pd3dImmediateContext->QueryInterface(IID_PPV_ARGS(&pd3dImmediateContext2)); if (SUCCEEDED(hr) && pd3dImmediateContext2) { GetDXUTState().SetD3D11DeviceContext2(pd3dImmediateContext2); } } } #endif #ifdef USE_DIRECT3D11_3 // Direct3D 11.3 { ID3D11Device3* pd3d11Device3 = nullptr; hr = pd3d11Device->QueryInterface( IID_PPV_ARGS(&pd3d11Device3) ); if (SUCCEEDED(hr) && pd3d11Device3) { GetDXUTState().SetD3D11Device3(pd3d11Device3); ID3D11DeviceContext3* pd3dImmediateContext3 = nullptr; hr = pd3dImmediateContext->QueryInterface(IID_PPV_ARGS(&pd3dImmediateContext3)); if (SUCCEEDED(hr) && pd3dImmediateContext3) { GetDXUTState().SetD3D11DeviceContext3(pd3dImmediateContext3); } } } #endif // If switching to REF, set the exit code to 11. If switching to HAL and exit code was 11, then set it back to 0. if( pNewDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE && GetDXUTState().GetExitCode() == 0 ) GetDXUTState().SetExitCode( 10 ); else if( pNewDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_HARDWARE && GetDXUTState().GetExitCode() == 10 ) GetDXUTState().SetExitCode( 0 ); // Update back buffer desc before calling app's device callbacks DXUTUpdateBackBufferDesc(); // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state) DXUTSetupCursor(); // Update the device stats text auto pd3dEnum = DXUTGetD3D11Enumeration(); assert( pd3dEnum ); _Analysis_assume_( pd3dEnum ); auto pAdapterInfo = pd3dEnum->GetAdapterInfo( pNewDeviceSettings->d3d11.AdapterOrdinal ); DXUTUpdateD3D11DeviceStats( pNewDeviceSettings->d3d11.DriverType, pNewDeviceSettings->d3d11.DeviceFeatureLevel, &pAdapterInfo->AdapterDesc ); // Call the app's device created callback if non-NULL auto pBackBufferSurfaceDesc = DXUTGetDXGIBackBufferSurfaceDesc(); GetDXUTState().SetInsideDeviceCallback( true ); auto pCallbackDeviceCreated = GetDXUTState().GetD3D11DeviceCreatedFunc(); hr = S_OK; if( pCallbackDeviceCreated ) hr = pCallbackDeviceCreated( DXUTGetD3D11Device(), pBackBufferSurfaceDesc, GetDXUTState().GetD3D11DeviceCreatedFuncUserContext() ); GetDXUTState().SetInsideDeviceCallback( false ); if( !DXUTGetD3D11Device() ) // Handle DXUTShutdown from inside callback return E_FAIL; if( FAILED( hr ) ) { DXUT_ERR( L"DeviceCreated callback", hr ); return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_CREATINGDEVICEOBJECTS; } GetDXUTState().SetDeviceObjectsCreated( true ); // Setup the render target view and viewport hr = DXUTCreateD3D11Views( pd3d11Device, pd3dImmediateContext, pNewDeviceSettings ); if( FAILED( hr ) ) { DXUT_ERR( L"DXUTCreateD3D11Views", hr ); return DXUTERR_CREATINGDEVICEOBJECTS; } // Call the app's swap chain reset callback if non-NULL GetDXUTState().SetInsideDeviceCallback( true ); LPDXUTCALLBACKD3D11SWAPCHAINRESIZED pCallbackSwapChainResized = GetDXUTState().GetD3D11SwapChainResizedFunc(); hr = S_OK; if( pCallbackSwapChainResized ) hr = pCallbackSwapChainResized( DXUTGetD3D11Device(), pSwapChain, pBackBufferSurfaceDesc, GetDXUTState().GetD3D11SwapChainResizedFuncUserContext() ); GetDXUTState().SetInsideDeviceCallback( false ); if( !DXUTGetD3D11Device() ) // Handle DXUTShutdown from inside callback return E_FAIL; if( FAILED( hr ) ) { DXUT_ERR( L"DeviceReset callback", hr ); return ( hr == DXUTERR_MEDIANOTFOUND ) ? DXUTERR_MEDIANOTFOUND : DXUTERR_RESETTINGDEVICEOBJECTS; } GetDXUTState().SetDeviceObjectsReset( true ); return S_OK; } //-------------------------------------------------------------------------------------- // Resets the 3D environment by: // - Calls the device lost callback // - Resets the device // - Stores the back buffer description // - Sets up the full screen Direct3D cursor if requested // - Calls the device reset callback //-------------------------------------------------------------------------------------- HRESULT DXUTReset3DEnvironment11() { HRESULT hr; GetDXUTState().SetDeviceObjectsReset( false ); DXUTPause( true, true ); bool bDeferredDXGIAction = false; auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); auto pSwapChain = DXUTGetDXGISwapChain(); assert( pSwapChain ); _Analysis_assume_( pSwapChain ); DXGI_SWAP_CHAIN_DESC SCDesc; if ( FAILED( pSwapChain->GetDesc(&SCDesc)) ) memset( &SCDesc, 0, sizeof(SCDesc) ); // Resize backbuffer and target of the swapchain in case they have changed. // For windowed mode, use the client rect as the desired size. Unlike D3D9, // we can't use 0 for width or height. Therefore, fill in the values from // the window size. For fullscreen mode, the width and height should have // already been filled with the desktop resolution, so don't change it. if( pDeviceSettings->d3d11.sd.Windowed && SCDesc.Windowed ) { RECT rcWnd; GetClientRect( DXUTGetHWND(), &rcWnd ); pDeviceSettings->d3d11.sd.BufferDesc.Width = rcWnd.right - rcWnd.left; pDeviceSettings->d3d11.sd.BufferDesc.Height = rcWnd.bottom - rcWnd.top; } // If the app wants to switch from windowed to fullscreen or vice versa, // call the swapchain's SetFullscreenState // mode. if( SCDesc.Windowed != pDeviceSettings->d3d11.sd.Windowed ) { // Set the fullscreen state if( pDeviceSettings->d3d11.sd.Windowed ) { V_RETURN( pSwapChain->SetFullscreenState( FALSE, nullptr ) ); bDeferredDXGIAction = true; } else { // Set fullscreen state by setting the display mode to fullscreen, then changing the resolution // to the desired value. // SetFullscreenState causes a WM_SIZE message to be sent to the window. The WM_SIZE message calls // DXUTCheckForDXGIBufferChange which normally stores the new height and width in // pDeviceSettings->d3d11.sd.BufferDesc. SetDoNotStoreBufferSize tells DXUTCheckForDXGIBufferChange // not to store the height and width so that we have the correct values when calling ResizeTarget. GetDXUTState().SetDoNotStoreBufferSize( true ); V_RETURN( pSwapChain->SetFullscreenState( TRUE, nullptr ) ); GetDXUTState().SetDoNotStoreBufferSize( false ); V_RETURN( pSwapChain->ResizeTarget( &pDeviceSettings->d3d11.sd.BufferDesc ) ); bDeferredDXGIAction = true; } } else { if( pDeviceSettings->d3d11.sd.BufferDesc.Width == SCDesc.BufferDesc.Width && pDeviceSettings->d3d11.sd.BufferDesc.Height == SCDesc.BufferDesc.Height && pDeviceSettings->d3d11.sd.BufferDesc.Format != SCDesc.BufferDesc.Format ) { DXUTResizeDXGIBuffers( 0, 0, !pDeviceSettings->d3d11.sd.Windowed ); bDeferredDXGIAction = true; } else if( pDeviceSettings->d3d11.sd.BufferDesc.Width != SCDesc.BufferDesc.Width || pDeviceSettings->d3d11.sd.BufferDesc.Height != SCDesc.BufferDesc.Height ) { V_RETURN( pSwapChain->ResizeTarget( &pDeviceSettings->d3d11.sd.BufferDesc ) ); bDeferredDXGIAction = true; } } // If no deferred DXGI actions are to take place, mark the device as reset. // If there is a deferred DXGI action, then the device isn't reset until DXGI sends us a // window message. Only then can we mark the device as reset. if( !bDeferredDXGIAction ) GetDXUTState().SetDeviceObjectsReset( true ); DXUTPause( false, false ); return S_OK; } //-------------------------------------------------------------------------------------- // Render the 3D environment by: // - Checking if the device is lost and trying to reset it if it is // - Get the elapsed time since the last frame // - Calling the app's framemove and render callback // - Calling Present() //-------------------------------------------------------------------------------------- void WINAPI DXUTRender3DEnvironment() { HRESULT hr; auto pd3dDevice = DXUTGetD3D11Device(); if( !pd3dDevice ) return; auto pd3dImmediateContext = DXUTGetD3D11DeviceContext(); if( !pd3dImmediateContext ) return; auto pSwapChain = DXUTGetDXGISwapChain(); if( !pSwapChain ) return; if( DXUTIsRenderingPaused() || !DXUTIsActive() || GetDXUTState().GetRenderingOccluded() ) { // Window is minimized/paused/occluded/or not exclusive so yield CPU time to other processes Sleep( 50 ); } // Get the app's time, in seconds. Skip rendering if no time elapsed double fTime, fAbsTime; float fElapsedTime; DXUTGetGlobalTimer()->GetTimeValues( &fTime, &fAbsTime, &fElapsedTime ); // Store the time for the app if( GetDXUTState().GetConstantFrameTime() ) { fElapsedTime = GetDXUTState().GetTimePerFrame(); fTime = DXUTGetTime() + fElapsedTime; } GetDXUTState().SetTime( fTime ); GetDXUTState().SetAbsoluteTime( fAbsTime ); GetDXUTState().SetElapsedTime( fElapsedTime ); // Update the FPS stats DXUTUpdateFrameStats(); DXUTHandleTimers(); // Animate the scene by calling the app's frame move callback LPDXUTCALLBACKFRAMEMOVE pCallbackFrameMove = GetDXUTState().GetFrameMoveFunc(); if( pCallbackFrameMove ) { pCallbackFrameMove( fTime, fElapsedTime, GetDXUTState().GetFrameMoveFuncUserContext() ); pd3dDevice = DXUTGetD3D11Device(); if( !pd3dDevice ) // Handle DXUTShutdown from inside callback return; } if( !GetDXUTState().GetRenderingPaused() ) { // Render the scene by calling the app's render callback LPDXUTCALLBACKD3D11FRAMERENDER pCallbackFrameRender = GetDXUTState().GetD3D11FrameRenderFunc(); if( pCallbackFrameRender && !GetDXUTState().GetRenderingOccluded() ) { pCallbackFrameRender( pd3dDevice, pd3dImmediateContext, fTime, fElapsedTime, GetDXUTState().GetD3D11FrameRenderFuncUserContext() ); pd3dDevice = DXUTGetD3D11Device(); if( !pd3dDevice ) // Handle DXUTShutdown from inside callback return; } #if defined(DEBUG) || defined(_DEBUG) // The back buffer should always match the client rect // if the Direct3D backbuffer covers the entire window RECT rcClient; GetClientRect( DXUTGetHWND(), &rcClient ); if( !IsIconic( DXUTGetHWND() ) ) { GetClientRect( DXUTGetHWND(), &rcClient ); assert( DXUTGetDXGIBackBufferSurfaceDesc()->Width == (UINT)rcClient.right ); assert( DXUTGetDXGIBackBufferSurfaceDesc()->Height == (UINT)rcClient.bottom ); } #endif } if ( GetDXUTState().GetSaveScreenShot() ) { DXUTSnapD3D11Screenshot( GetDXUTState().GetScreenShotName(), false ); } if ( GetDXUTState().GetExitAfterScreenShot() ) { DXUTShutdown(); return; } DWORD dwFlags = 0; if( GetDXUTState().GetRenderingOccluded() ) dwFlags = DXGI_PRESENT_TEST; else dwFlags = GetDXUTState().GetCurrentDeviceSettings()->d3d11.PresentFlags; UINT SyncInterval = GetDXUTState().GetCurrentDeviceSettings()->d3d11.SyncInterval; // Show the frame on the primary surface. hr = pSwapChain->Present( SyncInterval, dwFlags ); if( DXGI_STATUS_OCCLUDED == hr ) { // There is a window covering our entire rendering area. // Don't render until we're visible again. GetDXUTState().SetRenderingOccluded( true ); } else if( DXGI_ERROR_DEVICE_RESET == hr ) { // If a mode change happened, we must reset the device if( FAILED( hr = DXUTReset3DEnvironment11() ) ) { if( DXUTERR_RESETTINGDEVICEOBJECTS == hr || DXUTERR_MEDIANOTFOUND == hr ) { DXUTDisplayErrorMessage( hr ); DXUTShutdown(); return; } else { // Reset failed, but the device wasn't lost so something bad happened, // so recreate the device to try to recover auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); if( FAILED( DXUTChangeDevice( pDeviceSettings, false ) ) ) { DXUTShutdown(); return; } // How to handle display orientation changes in full-screen mode? } } } else if( DXGI_ERROR_DEVICE_REMOVED == hr ) { // Use a callback to ask the app if it would like to find a new device. // If no device removed callback is set, then look for a new device if( FAILED( DXUTHandleDeviceRemoved() ) ) { // Perhaps get more information from pD3DDevice->GetDeviceRemovedReason()? DXUTDisplayErrorMessage( DXUTERR_DEVICEREMOVED ); DXUTShutdown(); return; } } else if( SUCCEEDED( hr ) ) { if( GetDXUTState().GetRenderingOccluded() ) { // Now that we're no longer occluded // allow us to render again GetDXUTState().SetRenderingOccluded( false ); } } // Update current frame # int nFrame = GetDXUTState().GetCurrentFrameNumber(); nFrame++; GetDXUTState().SetCurrentFrameNumber( nFrame ); // Check to see if the app should shutdown due to cmdline if( GetDXUTState().GetOverrideQuitAfterFrame() != 0 ) { if( nFrame > GetDXUTState().GetOverrideQuitAfterFrame() ) DXUTShutdown(); } return; } //-------------------------------------------------------------------------------------- // Cleans up the 3D environment by: // - Calls the device lost callback // - Calls the device destroyed callback // - Releases the D3D device //-------------------------------------------------------------------------------------- void DXUTCleanup3DEnvironment( _In_ bool bReleaseSettings ) { auto pd3dDevice = DXUTGetD3D11Device(); if( pd3dDevice ) { if (GetDXUTState().GetD3D11RasterizerState()) GetDXUTState().GetD3D11RasterizerState()->Release(); // Call the app's SwapChain lost callback GetDXUTState().SetInsideDeviceCallback( true ); if( GetDXUTState().GetDeviceObjectsReset() ) { LPDXUTCALLBACKD3D11SWAPCHAINRELEASING pCallbackSwapChainReleasing = GetDXUTState().GetD3D11SwapChainReleasingFunc(); if( pCallbackSwapChainReleasing ) pCallbackSwapChainReleasing( GetDXUTState().GetD3D11SwapChainReleasingFuncUserContext() ); GetDXUTState().SetDeviceObjectsReset( false ); } // Release our old depth stencil texture and view auto pDS = GetDXUTState().GetD3D11DepthStencil(); SAFE_RELEASE( pDS ); GetDXUTState().SetD3D11DepthStencil( nullptr ); auto pDSV = GetDXUTState().GetD3D11DepthStencilView(); SAFE_RELEASE( pDSV ); GetDXUTState().SetD3D11DepthStencilView( nullptr ); // Cleanup the render target view auto pRTV = GetDXUTState().GetD3D11RenderTargetView(); SAFE_RELEASE( pRTV ); GetDXUTState().SetD3D11RenderTargetView( nullptr ); // Call the app's device destroyed callback if( GetDXUTState().GetDeviceObjectsCreated() ) { auto pCallbackDeviceDestroyed = GetDXUTState().GetD3D11DeviceDestroyedFunc(); if( pCallbackDeviceDestroyed ) pCallbackDeviceDestroyed( GetDXUTState().GetD3D11DeviceDestroyedFuncUserContext() ); GetDXUTState().SetDeviceObjectsCreated( false ); } GetDXUTState().SetInsideDeviceCallback( false ); // Release the swap chain GetDXUTState().SetReleasingSwapChain( true ); auto pSwapChain = DXUTGetDXGISwapChain(); if( pSwapChain ) { pSwapChain->SetFullscreenState( FALSE, 0 ); } SAFE_RELEASE( pSwapChain ); GetDXUTState().SetDXGISwapChain( nullptr ); GetDXUTState().SetReleasingSwapChain( false ); // Release the outputs. auto ppOutputArray = GetDXUTState().GetDXGIOutputArray(); UINT OutputCount = GetDXUTState().GetDXGIOutputArraySize(); for( UINT o = 0; o < OutputCount; ++o ) SAFE_RELEASE( ppOutputArray[o] ); delete[] ppOutputArray; GetDXUTState().SetDXGIOutputArray( nullptr ); GetDXUTState().SetDXGIOutputArraySize( 0 ); // Release the D3D adapter. auto pAdapter = GetDXUTState().GetDXGIAdapter(); SAFE_RELEASE( pAdapter ); GetDXUTState().SetDXGIAdapter( nullptr ); // Call ClearState to avoid tons of messy debug spew telling us that we're deleting bound objects auto pImmediateContext = DXUTGetD3D11DeviceContext(); assert( pImmediateContext ); pImmediateContext->ClearState(); pImmediateContext->Flush(); // Release the D3D11 immediate context (if it exists) because it has a extra ref count on it SAFE_RELEASE( pImmediateContext ); GetDXUTState().SetD3D11DeviceContext( nullptr ); auto pImmediateContext1 = DXUTGetD3D11DeviceContext1(); SAFE_RELEASE( pImmediateContext1 ); GetDXUTState().SetD3D11DeviceContext1( nullptr ); #ifdef USE_DIRECT3D11_2 auto pImmediateContext2 = DXUTGetD3D11DeviceContext2(); SAFE_RELEASE(pImmediateContext2); GetDXUTState().SetD3D11DeviceContext2(nullptr); #endif #ifdef USE_DIRECT3D11_3 auto pImmediateContext3 = DXUTGetD3D11DeviceContext3(); SAFE_RELEASE(pImmediateContext3); GetDXUTState().SetD3D11DeviceContext3(nullptr); #endif // Report live objects if ( pd3dDevice ) { #ifndef NDEBUG ID3D11Debug * d3dDebug = nullptr; if( SUCCEEDED( pd3dDevice->QueryInterface( IID_PPV_ARGS(&d3dDebug) ) ) ) { d3dDebug->ReportLiveDeviceObjects( D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL ); d3dDebug->Release(); } #endif auto pd3dDevice1 = DXUTGetD3D11Device1(); SAFE_RELEASE( pd3dDevice1 ); GetDXUTState().SetD3D11Device1(nullptr); #ifdef USE_DIRECT3D11_2 auto pd3dDevice2 = DXUTGetD3D11Device2(); SAFE_RELEASE(pd3dDevice2); GetDXUTState().SetD3D11Device2(nullptr); #endif #ifdef USE_DIRECT3D11_3 auto pd3dDevice3 = DXUTGetD3D11Device3(); SAFE_RELEASE(pd3dDevice3); GetDXUTState().SetD3D11Device3(nullptr); #endif // Release the D3D device and in debug configs, displays a message box if there // are unrelease objects. UINT references = pd3dDevice->Release(); if( references > 0 ) { DXUTDisplayErrorMessage( DXUTERR_NONZEROREFCOUNT ); DXUT_ERR( L"DXUTCleanup3DEnvironment", DXUTERR_NONZEROREFCOUNT ); } } GetDXUTState().SetD3D11Device( nullptr ); #ifndef NDEBUG { IDXGIDebug* dxgiDebug = nullptr; if ( SUCCEEDED( DXUT_Dynamic_DXGIGetDebugInterface( IID_IDXGIDebug, reinterpret_cast( &dxgiDebug ) ) ) ) { dxgiDebug->ReportLiveObjects( DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL ); dxgiDebug->Release(); } } #endif if( bReleaseSettings ) { auto pOldDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); SAFE_DELETE(pOldDeviceSettings); GetDXUTState().SetCurrentDeviceSettings( nullptr ); } auto pBackBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDescDXGI(); ZeroMemory( pBackBufferSurfaceDesc, sizeof( DXGI_SURFACE_DESC ) ); GetDXUTState().SetDeviceCreated( false ); } } //-------------------------------------------------------------------------------------- // Low level keyboard hook to disable Windows key to prevent accidental task switching. //-------------------------------------------------------------------------------------- LRESULT CALLBACK DXUTLowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) { if( nCode < 0 || nCode != HC_ACTION ) // do not process message return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam ); bool bEatKeystroke = false; auto p = reinterpret_cast( lParam ); switch( wParam ) { case WM_KEYDOWN: case WM_KEYUP: { bEatKeystroke = ( !GetDXUTState().GetAllowShortcutKeys() && ( p->vkCode == VK_LWIN || p->vkCode == VK_RWIN ) ); break; } } if( bEatKeystroke ) return 1; else return CallNextHookEx( GetDXUTState().GetKeyboardHook(), nCode, wParam, lParam ); } //-------------------------------------------------------------------------------------- // Controls how DXUT behaves when fullscreen and windowed mode with regard to // shortcut keys (Windows keys, StickyKeys shortcut, ToggleKeys shortcut, FilterKeys shortcut) //-------------------------------------------------------------------------------------- _Use_decl_annotations_ void WINAPI DXUTSetShortcutKeySettings( bool bAllowWhenFullscreen, bool bAllowWhenWindowed ) { GetDXUTState().SetAllowShortcutKeysWhenWindowed( bAllowWhenWindowed ); GetDXUTState().SetAllowShortcutKeysWhenFullscreen( bAllowWhenFullscreen ); // DXUTInit() records initial accessibility states so don't change them until then if( GetDXUTState().GetDXUTInited() ) { if( DXUTIsWindowed() ) DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenWindowed() ); else DXUTAllowShortcutKeys( GetDXUTState().GetAllowShortcutKeysWhenFullscreen() ); } } //-------------------------------------------------------------------------------------- // Enables/disables Windows keys, and disables or restores the StickyKeys/ToggleKeys/FilterKeys // shortcut to help prevent accidental task switching //-------------------------------------------------------------------------------------- void DXUTAllowShortcutKeys( _In_ bool bAllowKeys ) { GetDXUTState().SetAllowShortcutKeys( bAllowKeys ); if( bAllowKeys ) { // Restore StickyKeys/etc to original state and enable Windows key STICKYKEYS sk = GetDXUTState().GetStartupStickyKeys(); TOGGLEKEYS tk = GetDXUTState().GetStartupToggleKeys(); FILTERKEYS fk = GetDXUTState().GetStartupFilterKeys(); SystemParametersInfo( SPI_SETSTICKYKEYS, sizeof( STICKYKEYS ), &sk, 0 ); SystemParametersInfo( SPI_SETTOGGLEKEYS, sizeof( TOGGLEKEYS ), &tk, 0 ); SystemParametersInfo( SPI_SETFILTERKEYS, sizeof( FILTERKEYS ), &fk, 0 ); // Remove the keyboard hoook when it isn't needed to prevent any slow down of other apps if( GetDXUTState().GetKeyboardHook() ) { UnhookWindowsHookEx( GetDXUTState().GetKeyboardHook() ); GetDXUTState().SetKeyboardHook( nullptr ); } } else { // Set low level keyboard hook if haven't already if( !GetDXUTState().GetKeyboardHook() ) { // Set the low-level hook procedure. HHOOK hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, DXUTLowLevelKeyboardProc, GetModuleHandle( nullptr ), 0 ); GetDXUTState().SetKeyboardHook( hKeyboardHook ); } // Disable StickyKeys/etc shortcuts but if the accessibility feature is on, // then leave the settings alone as its probably being usefully used STICKYKEYS skOff = GetDXUTState().GetStartupStickyKeys(); if( ( skOff.dwFlags & SKF_STICKYKEYSON ) == 0 ) { // Disable the hotkey and the confirmation skOff.dwFlags &= ~SKF_HOTKEYACTIVE; skOff.dwFlags &= ~SKF_CONFIRMHOTKEY; SystemParametersInfo( SPI_SETSTICKYKEYS, sizeof( STICKYKEYS ), &skOff, 0 ); } TOGGLEKEYS tkOff = GetDXUTState().GetStartupToggleKeys(); if( ( tkOff.dwFlags & TKF_TOGGLEKEYSON ) == 0 ) { // Disable the hotkey and the confirmation tkOff.dwFlags &= ~TKF_HOTKEYACTIVE; tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY; SystemParametersInfo( SPI_SETTOGGLEKEYS, sizeof( TOGGLEKEYS ), &tkOff, 0 ); } FILTERKEYS fkOff = GetDXUTState().GetStartupFilterKeys(); if( ( fkOff.dwFlags & FKF_FILTERKEYSON ) == 0 ) { // Disable the hotkey and the confirmation fkOff.dwFlags &= ~FKF_HOTKEYACTIVE; fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY; SystemParametersInfo( SPI_SETFILTERKEYS, sizeof( FILTERKEYS ), &fkOff, 0 ); } } } //-------------------------------------------------------------------------------------- // Pauses time or rendering. Keeps a ref count so pausing can be layered //-------------------------------------------------------------------------------------- _Use_decl_annotations_ void WINAPI DXUTPause( bool bPauseTime, bool bPauseRendering ) { int nPauseTimeCount = GetDXUTState().GetPauseTimeCount(); if( bPauseTime ) nPauseTimeCount++; else nPauseTimeCount--; if( nPauseTimeCount < 0 ) nPauseTimeCount = 0; GetDXUTState().SetPauseTimeCount( nPauseTimeCount ); int nPauseRenderingCount = GetDXUTState().GetPauseRenderingCount(); if( bPauseRendering ) nPauseRenderingCount++; else nPauseRenderingCount--; if( nPauseRenderingCount < 0 ) nPauseRenderingCount = 0; GetDXUTState().SetPauseRenderingCount( nPauseRenderingCount ); if( nPauseTimeCount > 0 ) { // Stop the scene from animating DXUTGetGlobalTimer()->Stop(); } else { // Restart the timer DXUTGetGlobalTimer()->Start(); } GetDXUTState().SetRenderingPaused( nPauseRenderingCount > 0 ); GetDXUTState().SetTimePaused( nPauseTimeCount > 0 ); } //-------------------------------------------------------------------------------------- // Starts a user defined timer callback //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT WINAPI DXUTSetTimer( LPDXUTCALLBACKTIMER pCallbackTimer, float fTimeoutInSecs, UINT* pnIDEvent, void* pCallbackUserContext ) { if( !pCallbackTimer ) return DXUT_ERR_MSGBOX( L"DXUTSetTimer", E_INVALIDARG ); DXUT_TIMER DXUTTimer; DXUTTimer.pCallbackTimer = pCallbackTimer; DXUTTimer.pCallbackUserContext = pCallbackUserContext; DXUTTimer.fTimeoutInSecs = fTimeoutInSecs; DXUTTimer.fCountdown = fTimeoutInSecs; DXUTTimer.bEnabled = true; DXUTTimer.nID = GetDXUTState().GetTimerLastID() + 1; GetDXUTState().SetTimerLastID( DXUTTimer.nID ); auto pTimerList = GetDXUTState().GetTimerList(); if( !pTimerList ) { pTimerList = new (std::nothrow) std::vector; if( !pTimerList ) return E_OUTOFMEMORY; GetDXUTState().SetTimerList( pTimerList ); } pTimerList->push_back( DXUTTimer ); if( pnIDEvent ) *pnIDEvent = DXUTTimer.nID; return S_OK; } //-------------------------------------------------------------------------------------- // Stops a user defined timer callback //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTKillTimer( _In_ UINT nIDEvent ) { auto pTimerList = GetDXUTState().GetTimerList(); if( !pTimerList ) return S_FALSE; bool bFound = false; for( auto it = pTimerList->begin(); it != pTimerList->end(); ++it ) { DXUT_TIMER DXUTTimer = *it; if( DXUTTimer.nID == nIDEvent ) { DXUTTimer.bEnabled = false; *it = DXUTTimer; bFound = true; break; } } if( !bFound ) return DXUT_ERR_MSGBOX( L"DXUTKillTimer", E_INVALIDARG ); return S_OK; } //-------------------------------------------------------------------------------------- // Internal helper function to handle calling the user defined timer callbacks //-------------------------------------------------------------------------------------- void DXUTHandleTimers() { float fElapsedTime = DXUTGetElapsedTime(); auto pTimerList = GetDXUTState().GetTimerList(); if( !pTimerList ) return; // Walk through the list of timer callbacks for( auto it = pTimerList->begin(); it != pTimerList->end(); ++it ) { DXUT_TIMER DXUTTimer = *it; if( DXUTTimer.bEnabled ) { DXUTTimer.fCountdown -= fElapsedTime; // Call the callback if count down expired if( DXUTTimer.fCountdown < 0 ) { DXUTTimer.pCallbackTimer( DXUTTimer.nID, DXUTTimer.pCallbackUserContext ); // The callback my have changed the timer. DXUTTimer = *it; DXUTTimer.fCountdown = DXUTTimer.fTimeoutInSecs; } *it = DXUTTimer; } } } //-------------------------------------------------------------------------------------- // Display an custom error msg box //-------------------------------------------------------------------------------------- void DXUTDisplayErrorMessage( _In_ HRESULT hr ) { WCHAR strBuffer[512]; int nExitCode; bool bFound = true; switch( hr ) { case DXUTERR_NODIRECT3D: { nExitCode = 2; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Could not initialize Direct3D 11. " ); break; } case DXUTERR_NOCOMPATIBLEDEVICES: nExitCode = 3; if( GetSystemMetrics(SM_REMOTESESSION) != 0 ) wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Direct3D does not work over a remote session." ); else wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Could not find any compatible Direct3D devices." ); break; case DXUTERR_MEDIANOTFOUND: nExitCode = 4; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Could not find required media." ); break; case DXUTERR_NONZEROREFCOUNT: nExitCode = 5; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"The Direct3D device has a non-zero reference count, meaning some objects were not released." ); break; case DXUTERR_CREATINGDEVICE: nExitCode = 6; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Failed creating the Direct3D device." ); break; case DXUTERR_RESETTINGDEVICE: nExitCode = 7; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"Failed resetting the Direct3D device." ); break; case DXUTERR_CREATINGDEVICEOBJECTS: nExitCode = 8; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"An error occurred in the device create callback function." ); break; case DXUTERR_RESETTINGDEVICEOBJECTS: nExitCode = 9; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"An error occurred in the device reset callback function." ); break; // nExitCode 10 means the app exited using a REF device case DXUTERR_DEVICEREMOVED: nExitCode = 11; wcscpy_s( strBuffer, ARRAYSIZE(strBuffer), L"The Direct3D device was removed." ); break; default: bFound = false; nExitCode = 1; break; // nExitCode 1 means the API was incorrectly called } GetDXUTState().SetExitCode(nExitCode); bool bShowMsgBoxOnError = GetDXUTState().GetShowMsgBoxOnError(); if( bFound && bShowMsgBoxOnError ) { if( DXUTGetWindowTitle()[0] == 0 ) MessageBox( DXUTGetHWND(), strBuffer, L"DXUT Application", MB_ICONERROR | MB_OK ); else MessageBox( DXUTGetHWND(), strBuffer, DXUTGetWindowTitle(), MB_ICONERROR | MB_OK ); } } //-------------------------------------------------------------------------------------- // Internal function to map MK_* to an array index //-------------------------------------------------------------------------------------- int DXUTMapButtonToArrayIndex( _In_ BYTE vButton ) { switch( vButton ) { case MK_LBUTTON: return 0; case VK_MBUTTON: case MK_MBUTTON: return 1; case MK_RBUTTON: return 2; case VK_XBUTTON1: case MK_XBUTTON1: return 3; case VK_XBUTTON2: case MK_XBUTTON2: return 4; } return 0; } //-------------------------------------------------------------------------------------- // Toggle between full screen and windowed //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTToggleFullScreen() { auto deviceSettings = DXUTGetDeviceSettings(); if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_WARP ) { // WARP driver type doesn't support fullscreen return S_FALSE; } auto orginalDeviceSettings = DXUTGetDeviceSettings(); deviceSettings.d3d11.sd.Windowed = !deviceSettings.d3d11.sd.Windowed; HRESULT hr; if (!deviceSettings.d3d11.sd.Windowed) { DXGI_MODE_DESC adapterDesktopDisplayMode; hr = DXUTGetD3D11AdapterDisplayMode( deviceSettings.d3d11.AdapterOrdinal, 0, &adapterDesktopDisplayMode ); if ( FAILED(hr) ) { static const DXGI_MODE_DESC s_adapterDesktopDisplayMode = { 800, 600, { 0, 0 }, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB }; memcpy(&adapterDesktopDisplayMode, &s_adapterDesktopDisplayMode, sizeof(DXGI_MODE_DESC)); } deviceSettings.d3d11.sd.BufferDesc = adapterDesktopDisplayMode; } else { RECT r = DXUTGetWindowClientRectAtModeChange(); deviceSettings.d3d11.sd.BufferDesc.Height = r.bottom; deviceSettings.d3d11.sd.BufferDesc.Width = r.right; } hr = DXUTChangeDevice( &deviceSettings, false ); // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed if( FAILED( hr ) && ( hr != E_ABORT ) ) { // Failed creating device, try to switch back. HRESULT hr2 = DXUTChangeDevice( &orginalDeviceSettings, false ); if( FAILED( hr2 ) ) { // If this failed, then shutdown DXUTShutdown(); } } return hr; } //-------------------------------------------------------------------------------------- // Toggle between HAL/REF and WARP //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTToggleWARP () { auto deviceSettings = DXUTGetDeviceSettings(); if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_HARDWARE || deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE ) { if ( !deviceSettings.d3d11.sd.Windowed ) { // WARP driver type doesn't support fullscreen return S_FALSE; } deviceSettings.d3d11.DriverType = D3D_DRIVER_TYPE_WARP; } else if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_WARP ) { deviceSettings.d3d11.DriverType = D3D_DRIVER_TYPE_HARDWARE; } HRESULT hr = DXUTSnapDeviceSettingsToEnumDevice(&deviceSettings, false); if( SUCCEEDED( hr ) ) { DXUTDeviceSettings orginalDeviceSettings = DXUTGetDeviceSettings(); // Create a Direct3D device using the new device settings. // If there is an existing device, then it will either reset or recreate the scene. hr = DXUTChangeDevice( &deviceSettings, false ); // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed if( FAILED( hr ) && ( hr != E_ABORT ) ) { // Failed creating device, try to switch back. HRESULT hr2 = DXUTChangeDevice( &orginalDeviceSettings, false ); if( FAILED( hr2 ) ) { // If this failed, then shutdown DXUTShutdown(); } } } return hr; } //-------------------------------------------------------------------------------------- // Toggle between HAL/WARP and REF //-------------------------------------------------------------------------------------- HRESULT WINAPI DXUTToggleREF() { auto deviceSettings = DXUTGetDeviceSettings(); if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_HARDWARE ) { deviceSettings.d3d11.DriverType = D3D_DRIVER_TYPE_REFERENCE; } else if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE ) { deviceSettings.d3d11.DriverType = D3D_DRIVER_TYPE_HARDWARE; } else if ( deviceSettings.d3d11.DriverType == D3D_DRIVER_TYPE_WARP ) { if ( !deviceSettings.d3d11.sd.Windowed ) { // WARP driver type doesn't support fullscreen return S_FALSE; } deviceSettings.d3d11.DriverType = D3D_DRIVER_TYPE_REFERENCE; } HRESULT hr = DXUTSnapDeviceSettingsToEnumDevice(&deviceSettings, false); if( SUCCEEDED( hr ) ) { auto orginalDeviceSettings = DXUTGetDeviceSettings(); // Create a Direct3D device using the new device settings. // If there is an existing device, then it will either reset or recreate the scene. hr = DXUTChangeDevice( &deviceSettings, false ); // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback so nothing changed if( FAILED( hr ) && ( hr != E_ABORT ) ) { // Failed creating device, try to switch back. HRESULT hr2 = DXUTChangeDevice( &orginalDeviceSettings, false ); if( FAILED( hr2 ) ) { // If this failed, then shutdown DXUTShutdown(); } } } return hr; } //-------------------------------------------------------------------------------------- // Checks to see if DXGI has switched us out of fullscreen or windowed mode //-------------------------------------------------------------------------------------- void DXUTCheckForDXGIFullScreenSwitch() { auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); auto pSwapChain = DXUTGetDXGISwapChain(); assert( pSwapChain ); _Analysis_assume_( pSwapChain ); DXGI_SWAP_CHAIN_DESC SCDesc; if ( FAILED(pSwapChain->GetDesc(&SCDesc)) ) memset( &SCDesc, 0, sizeof(SCDesc) ); BOOL bIsWindowed = ( BOOL )DXUTIsWindowed(); if( bIsWindowed != SCDesc.Windowed ) { pDeviceSettings->d3d11.sd.Windowed = SCDesc.Windowed; auto deviceSettings = DXUTGetDeviceSettings(); if( bIsWindowed ) { GetDXUTState().SetWindowBackBufferWidthAtModeChange( deviceSettings.d3d11.sd.BufferDesc.Width ); GetDXUTState().SetWindowBackBufferHeightAtModeChange( deviceSettings.d3d11.sd.BufferDesc.Height ); } else { GetDXUTState().SetFullScreenBackBufferWidthAtModeChange( deviceSettings.d3d11.sd.BufferDesc.Width ); GetDXUTState().SetFullScreenBackBufferHeightAtModeChange( deviceSettings.d3d11.sd.BufferDesc.Height ); } } } _Use_decl_annotations_ void DXUTResizeDXGIBuffers( UINT Width, UINT Height, BOOL bFullScreen ) { HRESULT hr = S_OK; RECT rcCurrentClient; GetClientRect( DXUTGetHWND(), &rcCurrentClient ); auto pDevSettings = GetDXUTState().GetCurrentDeviceSettings(); assert( pDevSettings ); _Analysis_assume_( pDevSettings ); auto pSwapChain = DXUTGetDXGISwapChain(); auto pd3dDevice = DXUTGetD3D11Device(); assert( pd3dDevice ); _Analysis_assume_( pd3dDevice ); auto pd3dImmediateContext = DXUTGetD3D11DeviceContext(); assert( pd3dImmediateContext ); _Analysis_assume_( pd3dImmediateContext ); // Determine if we're fullscreen pDevSettings->d3d11.sd.Windowed = !bFullScreen; // Call releasing GetDXUTState().SetInsideDeviceCallback( true ); LPDXUTCALLBACKD3D11SWAPCHAINRELEASING pCallbackSwapChainReleasing = GetDXUTState().GetD3D11SwapChainReleasingFunc (); if( pCallbackSwapChainReleasing ) pCallbackSwapChainReleasing( GetDXUTState().GetD3D11SwapChainResizedFuncUserContext() ); GetDXUTState().SetInsideDeviceCallback( false ); // Release our old depth stencil texture and view auto pDS = GetDXUTState().GetD3D11DepthStencil(); SAFE_RELEASE( pDS ); GetDXUTState().SetD3D11DepthStencil( nullptr ); auto pDSV = GetDXUTState().GetD3D11DepthStencilView(); SAFE_RELEASE( pDSV ); GetDXUTState().SetD3D11DepthStencilView( nullptr ); // Release our old render target view auto pRTV = GetDXUTState().GetD3D11RenderTargetView(); SAFE_RELEASE( pRTV ); GetDXUTState().SetD3D11RenderTargetView( nullptr ); // Alternate between 0 and DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH when resizing buffers. // When in windowed mode, we want 0 since this allows the app to change to the desktop // resolution from windowed mode during alt+enter. However, in fullscreen mode, we want // the ability to change display modes from the Device Settings dialog. Therefore, we // want to set the DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH flag. UINT Flags = 0; if( bFullScreen ) Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // ResizeBuffers V( pSwapChain->ResizeBuffers( pDevSettings->d3d11.sd.BufferCount, Width, Height, pDevSettings->d3d11.sd.BufferDesc.Format, Flags ) ); if( !GetDXUTState().GetDoNotStoreBufferSize() ) { pDevSettings->d3d11.sd.BufferDesc.Width = ( UINT )rcCurrentClient.right; pDevSettings->d3d11.sd.BufferDesc.Height = ( UINT )rcCurrentClient.bottom; } // Save off backbuffer desc DXUTUpdateBackBufferDesc(); // Update the device stats text DXUTUpdateStaticFrameStats(); // Setup the render target view and viewport hr = DXUTCreateD3D11Views( pd3dDevice, pd3dImmediateContext, pDevSettings ); if( FAILED( hr ) ) { DXUT_ERR( L"DXUTCreateD3D11Views", hr ); return; } // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state) DXUTSetupCursor(); // Call the app's SwapChain reset callback GetDXUTState().SetInsideDeviceCallback( true ); auto pBackBufferSurfaceDesc = DXUTGetDXGIBackBufferSurfaceDesc(); LPDXUTCALLBACKD3D11SWAPCHAINRESIZED pCallbackSwapChainResized = GetDXUTState().GetD3D11SwapChainResizedFunc(); hr = S_OK; if( pCallbackSwapChainResized ) hr = pCallbackSwapChainResized( pd3dDevice, pSwapChain, pBackBufferSurfaceDesc, GetDXUTState().GetD3D11SwapChainResizedFuncUserContext() ); GetDXUTState().SetInsideDeviceCallback( false ); if( FAILED( hr ) ) { // If callback failed, cleanup DXUT_ERR( L"DeviceResetCallback", hr ); if( hr != DXUTERR_MEDIANOTFOUND ) hr = DXUTERR_RESETTINGDEVICEOBJECTS; GetDXUTState().SetInsideDeviceCallback( true ); pCallbackSwapChainReleasing = GetDXUTState().GetD3D11SwapChainReleasingFunc(); if( pCallbackSwapChainReleasing ) pCallbackSwapChainReleasing( GetDXUTState().GetD3D11SwapChainResizedFuncUserContext() ); GetDXUTState().SetInsideDeviceCallback( false ); DXUTPause( false, false ); PostQuitMessage( 0 ); } else { GetDXUTState().SetDeviceObjectsReset( true ); DXUTPause( false, false ); } } //-------------------------------------------------------------------------------------- // Checks if DXGI buffers need to change //-------------------------------------------------------------------------------------- void DXUTCheckForDXGIBufferChange() { if(DXUTGetDXGISwapChain() && !GetDXUTState().GetReleasingSwapChain() ) { //DXUTgetdxgi auto pSwapChain = DXUTGetDXGISwapChain(); assert(pSwapChain); _Analysis_assume_(pSwapChain); // workaround for SAL bug in DXGI header #pragma warning(push) #pragma warning( disable:4616 6309 6387 ) // Determine if we're fullscreen BOOL bFullScreen; if ( FAILED(pSwapChain->GetFullscreenState(&bFullScreen, nullptr)) ) bFullScreen = FALSE; #pragma warning(pop) DXUTResizeDXGIBuffers( 0, 0, bFullScreen ); ShowWindow( DXUTGetHWND(), SW_SHOW ); } } //-------------------------------------------------------------------------------------- // Checks if the window client rect has changed and if it has, then reset the device //-------------------------------------------------------------------------------------- void DXUTCheckForWindowSizeChange() { // Skip the check for various reasons if( GetDXUTState().GetIgnoreSizeChange() || !GetDXUTState().GetDeviceCreated() ) return; DXUTCheckForDXGIBufferChange(); } //-------------------------------------------------------------------------------------- // Checks to see if the HWND changed monitors, and if it did it creates a device // from the monitor's adapter and recreates the scene. //-------------------------------------------------------------------------------------- void DXUTCheckForWindowChangingMonitors() { // Skip this check for various reasons if( !GetDXUTState().GetAutoChangeAdapter() || GetDXUTState().GetIgnoreSizeChange() || !GetDXUTState().GetDeviceCreated() || !DXUTIsWindowed() ) return; HRESULT hr; HMONITOR hWindowMonitor = DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTOPRIMARY ); HMONITOR hAdapterMonitor = GetDXUTState().GetAdapterMonitor(); if( hWindowMonitor != hAdapterMonitor ) { UINT newOrdinal; if( SUCCEEDED( DXUTGetAdapterOrdinalFromMonitor( hWindowMonitor, &newOrdinal ) ) ) { // Find the closest valid device settings with the new ordinal auto deviceSettings = DXUTGetDeviceSettings(); deviceSettings.d3d11.AdapterOrdinal = newOrdinal; UINT newOutput; if( SUCCEEDED( DXUTGetOutputOrdinalFromMonitor( hWindowMonitor, &newOutput ) ) ) deviceSettings.d3d11.Output = newOutput; hr = DXUTSnapDeviceSettingsToEnumDevice( &deviceSettings, false ); if( SUCCEEDED( hr ) ) { // Create a Direct3D device using the new device settings. // If there is an existing device, then it will either reset or recreate the scene. hr = DXUTChangeDevice( &deviceSettings, false ); // If hr == E_ABORT, this means the app rejected the device settings in the ModifySettingsCallback if( hr == E_ABORT ) { // so nothing changed and keep from attempting to switch adapters next time GetDXUTState().SetAutoChangeAdapter( false ); } else if( FAILED( hr ) ) { DXUTShutdown(); DXUTPause( false, false ); return; } } } } } //-------------------------------------------------------------------------------------- // Returns the HMONITOR attached to an adapter/output //-------------------------------------------------------------------------------------- HMONITOR DXUTGetMonitorFromAdapter( _In_ DXUTDeviceSettings* pDeviceSettings ) { auto pD3DEnum = DXUTGetD3D11Enumeration(); assert( pD3DEnum ); _Analysis_assume_( pD3DEnum ); auto pOutputInfo = pD3DEnum->GetOutputInfo( pDeviceSettings->d3d11.AdapterOrdinal, pDeviceSettings->d3d11.Output ); if( !pOutputInfo ) return 0; return DXUTMonitorFromRect( &pOutputInfo->Desc.DesktopCoordinates, MONITOR_DEFAULTTONEAREST ); } //-------------------------------------------------------------------------------------- // Look for an adapter ordinal that is tied to a HMONITOR //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DXUTGetAdapterOrdinalFromMonitor( HMONITOR hMonitor, UINT* pAdapterOrdinal ) { *pAdapterOrdinal = 0; // Get the monitor handle information MONITORINFOEX mi; mi.cbSize = sizeof( MONITORINFOEX ); DXUTGetMonitorInfo( hMonitor, &mi ); // Search for this monitor in our enumeration hierarchy. auto pd3dEnum = DXUTGetD3D11Enumeration(); auto pAdapterList = pd3dEnum->GetAdapterInfoList(); for( auto it = pAdapterList->cbegin(); it != pAdapterList->cend(); ++it ) { auto pAdapterInfo = *it; for( auto jit = pAdapterInfo->outputInfoList.cbegin(); jit != pAdapterInfo->outputInfoList.cend(); ++jit ) { auto pOutputInfo = *jit; // Convert output device name from MBCS to Unicode if( wcsncmp( pOutputInfo->Desc.DeviceName, mi.szDevice, sizeof( mi.szDevice ) / sizeof ( mi.szDevice[0] ) ) == 0 ) { *pAdapterOrdinal = pAdapterInfo->AdapterOrdinal; return S_OK; } } } return E_FAIL; } //-------------------------------------------------------------------------------------- // Look for a monitor ordinal that is tied to a HMONITOR (D3D11-only) //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DXUTGetOutputOrdinalFromMonitor( HMONITOR hMonitor, UINT* pOutputOrdinal ) { // Get the monitor handle information MONITORINFOEX mi; mi.cbSize = sizeof( MONITORINFOEX ); DXUTGetMonitorInfo( hMonitor, &mi ); // Search for this monitor in our enumeration hierarchy. auto pd3dEnum = DXUTGetD3D11Enumeration(); auto pAdapterList = pd3dEnum->GetAdapterInfoList(); for( auto it = pAdapterList->cbegin(); it != pAdapterList->cend(); ++it ) { auto pAdapterInfo = *it; for( auto jit = pAdapterInfo->outputInfoList.cbegin(); jit != pAdapterInfo->outputInfoList.cend(); ++jit ) { auto pOutputInfo = *jit; DXGI_OUTPUT_DESC Desc; if ( FAILED(pOutputInfo->m_pOutput->GetDesc(&Desc)) ) memset( &Desc, 0, sizeof(Desc) ); if( hMonitor == Desc.Monitor ) { *pOutputOrdinal = pOutputInfo->Output; return S_OK; } } } return E_FAIL; } //-------------------------------------------------------------------------------------- // This method is called when D3DERR_DEVICEREMOVED is returned from an API. DXUT // calls the application's DeviceRemoved callback to inform it of the event. The // application returns true if it wants DXUT to look for a closest device to run on. // If no device is found, or the app returns false, DXUT shuts down. //-------------------------------------------------------------------------------------- HRESULT DXUTHandleDeviceRemoved() { HRESULT hr = S_OK; // Device has been removed. Call the application's callback if set. If no callback // has been set, then just look for a new device bool bLookForNewDevice = true; LPDXUTCALLBACKDEVICEREMOVED pDeviceRemovedFunc = GetDXUTState().GetDeviceRemovedFunc(); if( pDeviceRemovedFunc ) bLookForNewDevice = pDeviceRemovedFunc( GetDXUTState().GetDeviceRemovedFuncUserContext() ); if( bLookForNewDevice ) { auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); hr = DXUTSnapDeviceSettingsToEnumDevice( pDeviceSettings, false); if( SUCCEEDED( hr ) ) { // Change to a Direct3D device created from the new device settings // that is compatible with the removed device. hr = DXUTChangeDevice( pDeviceSettings, false ); if( SUCCEEDED( hr ) ) return S_OK; } } // The app does not wish to continue or continuing is not possible. return DXUTERR_DEVICEREMOVED; } //-------------------------------------------------------------------------------------- // Stores back buffer surface desc in GetDXUTState().GetBackBufferSurfaceDesc10() //-------------------------------------------------------------------------------------- void DXUTUpdateBackBufferDesc() { HRESULT hr; ID3D11Texture2D* pBackBuffer; auto pSwapChain = GetDXUTState().GetDXGISwapChain(); assert( pSwapChain ); _Analysis_assume_( pSwapChain ); hr = pSwapChain->GetBuffer( 0, IID_PPV_ARGS(&pBackBuffer) ); auto pBBufferSurfaceDesc = GetDXUTState().GetBackBufferSurfaceDescDXGI(); ZeroMemory( pBBufferSurfaceDesc, sizeof( DXGI_SURFACE_DESC ) ); if( SUCCEEDED( hr ) ) { D3D11_TEXTURE2D_DESC TexDesc; pBackBuffer->GetDesc( &TexDesc ); pBBufferSurfaceDesc->Width = ( UINT )TexDesc.Width; pBBufferSurfaceDesc->Height = ( UINT )TexDesc.Height; pBBufferSurfaceDesc->Format = TexDesc.Format; pBBufferSurfaceDesc->SampleDesc = TexDesc.SampleDesc; SAFE_RELEASE( pBackBuffer ); } } //-------------------------------------------------------------------------------------- // Setup cursor based on current settings (window/fullscreen mode, show cursor state, clip cursor state) //-------------------------------------------------------------------------------------- void DXUTSetupCursor() { // Clip cursor if requested if( !DXUTIsWindowed() && GetDXUTState().GetClipCursorWhenFullScreen() ) { // Confine cursor to full screen window RECT rcWindow; GetWindowRect( DXUTGetHWNDDeviceFullScreen(), &rcWindow ); ClipCursor( &rcWindow ); } else { ClipCursor( nullptr ); } } //-------------------------------------------------------------------------------------- // Updates the static part of the frame stats so it doesn't have be generated every frame //-------------------------------------------------------------------------------------- void DXUTUpdateStaticFrameStats() { if( GetDXUTState().GetNoStats() ) return; auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); if( !pDeviceSettings ) return; // D3D11 auto pd3dEnum = DXUTGetD3D11Enumeration(); if( !pd3dEnum ) return; auto pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->d3d11.AdapterOrdinal, pDeviceSettings->d3d11.sd.BufferDesc.Format, pDeviceSettings->d3d11.sd.Windowed ); if( !pDeviceSettingsCombo ) return; WCHAR strFmt[100]; wcscpy_s( strFmt, 100, DXUTDXGIFormatToString( pDeviceSettingsCombo->BackBufferFormat, false ) ); WCHAR strMultiSample[100]; swprintf_s( strMultiSample, 100, L" (MS%u, Q%u)", pDeviceSettings->d3d11.sd.SampleDesc.Count, pDeviceSettings->d3d11.sd.SampleDesc.Quality ); auto pstrStaticFrameStats = GetDXUTState().GetStaticFrameStats(); swprintf_s( pstrStaticFrameStats, 256, L"D3D11 %%ls Vsync %ls (%ux%u), %ls%ls", ( pDeviceSettings->d3d11.SyncInterval == 0 ) ? L"off" : L"on", pDeviceSettings->d3d11.sd.BufferDesc.Width, pDeviceSettings->d3d11.sd.BufferDesc.Height, strFmt, strMultiSample ); } //-------------------------------------------------------------------------------------- // Updates the frames/sec stat once per second //-------------------------------------------------------------------------------------- void DXUTUpdateFrameStats() { if( GetDXUTState().GetNoStats() ) return; // Keep track of the frame count double fLastTime = GetDXUTState().GetLastStatsUpdateTime(); DWORD dwFrames = GetDXUTState().GetLastStatsUpdateFrames(); double fAbsTime = GetDXUTState().GetAbsoluteTime(); dwFrames++; GetDXUTState().SetLastStatsUpdateFrames( dwFrames ); // Update the scene stats once per second if( fAbsTime - fLastTime > 1.0f ) { float fFPS = ( float )( dwFrames / ( fAbsTime - fLastTime ) ); GetDXUTState().SetFPS( fFPS ); GetDXUTState().SetLastStatsUpdateTime( fAbsTime ); GetDXUTState().SetLastStatsUpdateFrames( 0 ); auto pstrFPS = GetDXUTState().GetFPSStats(); swprintf_s( pstrFPS, 64, L"%0.2f fps ", fFPS ); } } //-------------------------------------------------------------------------------------- // Returns a string describing the current device. If bShowFPS is true, then // the string contains the frames/sec. If "-nostats" was used in // the command line, the string will be blank //-------------------------------------------------------------------------------------- LPCWSTR WINAPI DXUTGetFrameStats( _In_ bool bShowFPS ) { auto pstrFrameStats = GetDXUTState().GetFrameStats(); const WCHAR* pstrFPS = ( bShowFPS ) ? GetDXUTState().GetFPSStats() : L""; WCHAR* pstrStats = GetDXUTState().GetStaticFrameStats(); swprintf_s( pstrFrameStats, 256, pstrStats, pstrFPS ); return pstrFrameStats; } //-------------------------------------------------------------------------------------- // Updates the string which describes the device //-------------------------------------------------------------------------------------- #pragma warning( suppress : 6101 ) _Use_decl_annotations_ void DXUTUpdateD3D11DeviceStats( D3D_DRIVER_TYPE DeviceType, D3D_FEATURE_LEVEL featureLevel, DXGI_ADAPTER_DESC* pAdapterDesc ) { if( GetDXUTState().GetNoStats() ) return; // Store device description auto pstrDeviceStats = GetDXUTState().GetDeviceStats(); if( DeviceType == D3D_DRIVER_TYPE_REFERENCE ) wcscpy_s( pstrDeviceStats, 256, L"REFERENCE" ); else if( DeviceType == D3D_DRIVER_TYPE_HARDWARE ) wcscpy_s( pstrDeviceStats, 256, L"HARDWARE" ); else if( DeviceType == D3D_DRIVER_TYPE_SOFTWARE ) wcscpy_s( pstrDeviceStats, 256, L"SOFTWARE" ); else if( DeviceType == D3D_DRIVER_TYPE_WARP ) wcscpy_s( pstrDeviceStats, 256, L"WARP" ); if( DeviceType == D3D_DRIVER_TYPE_HARDWARE ) { // Be sure not to overflow m_strDeviceStats when appending the adapter // description, since it can be long. wcscat_s( pstrDeviceStats, 256, L": " ); // Try to get a unique description from the CD3D11EnumDeviceSettingsCombo auto pDeviceSettings = GetDXUTState().GetCurrentDeviceSettings(); if( !pDeviceSettings ) return; auto pd3dEnum = DXUTGetD3D11Enumeration(); assert( pd3dEnum ); _Analysis_assume_( pd3dEnum ); auto pDeviceSettingsCombo = pd3dEnum->GetDeviceSettingsCombo( pDeviceSettings->d3d11.AdapterOrdinal, pDeviceSettings->d3d11.sd.BufferDesc.Format, pDeviceSettings->d3d11.sd.Windowed ); if( pDeviceSettingsCombo ) wcscat_s( pstrDeviceStats, 256, pDeviceSettingsCombo->pAdapterInfo->szUniqueDescription ); else wcscat_s( pstrDeviceStats, 256, pAdapterDesc->Description ); } switch( featureLevel ) { case D3D_FEATURE_LEVEL_9_1: wcscat_s( pstrDeviceStats, 256, L" (FL 9.1)" ); break; case D3D_FEATURE_LEVEL_9_2: wcscat_s( pstrDeviceStats, 256, L" (FL 9.2)" ); break; case D3D_FEATURE_LEVEL_9_3: wcscat_s( pstrDeviceStats, 256, L" (FL 9.3)" ); break; case D3D_FEATURE_LEVEL_10_0: wcscat_s( pstrDeviceStats, 256, L" (FL 10.0)" ); break; case D3D_FEATURE_LEVEL_10_1: wcscat_s( pstrDeviceStats, 256, L" (FL 10.1)" ); break; case D3D_FEATURE_LEVEL_11_0: wcscat_s( pstrDeviceStats, 256, L" (FL 11.0)" ); break; case D3D_FEATURE_LEVEL_11_1: wcscat_s( pstrDeviceStats, 256, L" (FL 11.1)" ); break; #ifdef USE_DIRECT3D11_3 case D3D_FEATURE_LEVEL_12_0: wcscat_s(pstrDeviceStats, 256, L" (FL 12.0)"); break; case D3D_FEATURE_LEVEL_12_1: wcscat_s(pstrDeviceStats, 256, L" (FL 12.1)"); break; #endif } } //-------------------------------------------------------------------------------------- // Misc functions //-------------------------------------------------------------------------------------- DXUTDeviceSettings WINAPI DXUTGetDeviceSettings() { // Return a copy of device settings of the current device. If no device exists yet, then // return a blank device settings struct auto pDS = GetDXUTState().GetCurrentDeviceSettings(); if( pDS ) { return *pDS; } else { DXUTDeviceSettings ds; ZeroMemory( &ds, sizeof( DXUTDeviceSettings ) ); return ds; } } bool WINAPI DXUTIsVsyncEnabled() { auto pDS = GetDXUTState().GetCurrentDeviceSettings(); if( pDS ) { return ( pDS->d3d11.SyncInterval == 0 ); } else { return true; } }; bool WINAPI DXUTIsKeyDown( _In_ BYTE vKey ) { bool* bKeys = GetDXUTState().GetKeys(); if( vKey >= 0xA0 && vKey <= 0xA5 ) // VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU return GetAsyncKeyState( vKey ) != 0; // these keys only are tracked via GetAsyncKeyState() else if( vKey >= 0x01 && vKey <= 0x06 && vKey != 0x03 ) // mouse buttons (VK_*BUTTON) return DXUTIsMouseButtonDown( vKey ); else return bKeys[vKey]; } bool WINAPI DXUTWasKeyPressed( _In_ BYTE vKey ) { bool* bLastKeys = GetDXUTState().GetLastKeys(); bool* bKeys = GetDXUTState().GetKeys(); GetDXUTState().SetAppCalledWasKeyPressed( true ); return ( !bLastKeys[vKey] && bKeys[vKey] ); } bool WINAPI DXUTIsMouseButtonDown( _In_ BYTE vButton ) { bool* bMouseButtons = GetDXUTState().GetMouseButtons(); int nIndex = DXUTMapButtonToArrayIndex( vButton ); return bMouseButtons[nIndex]; } void WINAPI DXUTSetMultimonSettings( _In_ bool bAutoChangeAdapter ) { GetDXUTState().SetAutoChangeAdapter( bAutoChangeAdapter ); } _Use_decl_annotations_ void WINAPI DXUTSetHotkeyHandling( bool bAltEnterToToggleFullscreen, bool bEscapeToQuit, bool bPauseToToggleTimePause ) { GetDXUTState().SetHandleEscape( bEscapeToQuit ); GetDXUTState().SetHandleAltEnter( bAltEnterToToggleFullscreen ); GetDXUTState().SetHandlePause( bPauseToToggleTimePause ); } _Use_decl_annotations_ void WINAPI DXUTSetCursorSettings( bool bShowCursorWhenFullScreen, bool bClipCursorWhenFullScreen ) { GetDXUTState().SetClipCursorWhenFullScreen( bClipCursorWhenFullScreen ); GetDXUTState().SetShowCursorWhenFullScreen( bShowCursorWhenFullScreen ); DXUTSetupCursor(); } void WINAPI DXUTSetWindowSettings( _In_ bool bCallDefWindowProc ) { GetDXUTState().SetCallDefWindowProc( bCallDefWindowProc ); } _Use_decl_annotations_ void WINAPI DXUTSetConstantFrameTime( bool bEnabled, float fTimePerFrame ) { if( GetDXUTState().GetOverrideConstantFrameTime() ) { bEnabled = GetDXUTState().GetOverrideConstantFrameTime(); fTimePerFrame = GetDXUTState().GetOverrideConstantTimePerFrame(); } GetDXUTState().SetConstantFrameTime( bEnabled ); GetDXUTState().SetTimePerFrame( fTimePerFrame ); } //-------------------------------------------------------------------------------------- // Resets the state associated with DXUT //-------------------------------------------------------------------------------------- void WINAPI DXUTResetFrameworkState() { GetDXUTState().Destroy(); GetDXUTState().Create(); } //-------------------------------------------------------------------------------------- // Closes down the window. When the window closes, it will cleanup everything //-------------------------------------------------------------------------------------- void WINAPI DXUTShutdown( _In_ int nExitCode ) { HWND hWnd = DXUTGetHWND(); if( hWnd ) SendMessage( hWnd, WM_CLOSE, 0, 0 ); GetDXUTState().SetExitCode( nExitCode ); DXUTCleanup3DEnvironment( true ); // Restore shortcut keys (Windows key, accessibility shortcuts) to original state // This is important to call here if the shortcuts are disabled, // because accessibility setting changes are permanent. // This means that if this is not done then the accessibility settings // might not be the same as when the app was started. // If the app crashes without restoring the settings, this is also true so it // would be wise to backup/restore the settings from a file so they can be // restored when the crashed app is run again. DXUTAllowShortcutKeys( true ); // Shutdown D3D11 auto pDXGIFactory = GetDXUTState().GetDXGIFactory(); SAFE_RELEASE( pDXGIFactory ); GetDXUTState().SetDXGIFactory( nullptr ); } //-------------------------------------------------------------------------------------- // Tells DXUT whether to operate in gamma correct mode //-------------------------------------------------------------------------------------- void WINAPI DXUTSetIsInGammaCorrectMode( _In_ bool bGammaCorrect ) { GetDXUTState().SetIsInGammaCorrectMode( bGammaCorrect ); } //-------------------------------------------------------------------------------------- void DXUTApplyDefaultDeviceSettings(DXUTDeviceSettings *modifySettings) { ZeroMemory( modifySettings, sizeof( DXUTDeviceSettings ) ); modifySettings->d3d11.AdapterOrdinal = 0; modifySettings->d3d11.AutoCreateDepthStencil = true; modifySettings->d3d11.AutoDepthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; #if defined(DEBUG) || defined(_DEBUG) modifySettings->d3d11.CreateFlags |= D3D11_CREATE_DEVICE_DEBUG; #else modifySettings->d3d11.CreateFlags = 0; #endif modifySettings->d3d11.DriverType = D3D_DRIVER_TYPE_HARDWARE; modifySettings->d3d11.Output = 0; modifySettings->d3d11.PresentFlags = 0; modifySettings->d3d11.sd.BufferCount = 2; modifySettings->d3d11.sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; modifySettings->d3d11.sd.BufferDesc.Height = 600; modifySettings->d3d11.sd.BufferDesc.RefreshRate.Numerator = 0; modifySettings->d3d11.sd.BufferDesc.RefreshRate.Denominator = 0; modifySettings->d3d11.sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; modifySettings->d3d11.sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; modifySettings->d3d11.sd.BufferDesc.Width = 800; modifySettings->d3d11.sd.BufferUsage = 32; modifySettings->d3d11.sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH ; modifySettings->d3d11.sd.OutputWindow = DXUTGetHWND(); modifySettings->d3d11.sd.SampleDesc.Count = 1; modifySettings->d3d11.sd.SampleDesc.Quality = 0; modifySettings->d3d11.sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; modifySettings->d3d11.sd.Windowed = TRUE; modifySettings->d3d11.SyncInterval = 0; } //-------------------------------------------------------------------------------------- // Update settings based on what is enumeratabled //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DXUTSnapDeviceSettingsToEnumDevice( DXUTDeviceSettings* pDeviceSettings, bool forceEnum, D3D_FEATURE_LEVEL forceFL ) { if( GetSystemMetrics(SM_REMOTESESSION) != 0 ) { pDeviceSettings->d3d11.sd.Windowed = TRUE; } int bestModeIndex=0; int bestMSAAIndex=0; //DXUTSetDefaultDeviceSettings CD3D11Enumeration *pEnum = DXUTGetD3D11Enumeration( forceEnum, true, forceFL); CD3D11EnumAdapterInfo* pAdapterInfo = nullptr; auto pAdapterList = pEnum->GetAdapterInfoList(); for( auto it = pAdapterList->cbegin(); it != pAdapterList->cend(); ++it ) { auto tempAdapterInfo = *it; if (tempAdapterInfo->AdapterOrdinal == pDeviceSettings->d3d11.AdapterOrdinal) pAdapterInfo = tempAdapterInfo; } if ( !pAdapterInfo ) { if ( pAdapterList->empty() || pDeviceSettings->d3d11.AdapterOrdinal > 0 ) { return E_FAIL; // no adapters found. } pAdapterInfo = *pAdapterList->cbegin(); } CD3D11EnumDeviceSettingsCombo* pDeviceSettingsCombo = nullptr; float biggestScore = 0; for( size_t iDeviceCombo = 0; iDeviceCombo < pAdapterInfo->deviceSettingsComboList.size(); iDeviceCombo++ ) { CD3D11EnumDeviceSettingsCombo* tempDeviceSettingsCombo = pAdapterInfo->deviceSettingsComboList[ iDeviceCombo ]; int bestMode; int bestMSAA; float score = DXUTRankD3D11DeviceCombo(tempDeviceSettingsCombo, &(pDeviceSettings->d3d11), bestMode, bestMSAA ); if (score > biggestScore) { biggestScore = score; pDeviceSettingsCombo = tempDeviceSettingsCombo; bestModeIndex = bestMode; bestMSAAIndex = bestMSAA; } } if (!pDeviceSettingsCombo ) { return E_FAIL; // no settings found. } pDeviceSettings->d3d11.AdapterOrdinal = pDeviceSettingsCombo->AdapterOrdinal; pDeviceSettings->d3d11.DriverType = pDeviceSettingsCombo->DeviceType; pDeviceSettings->d3d11.Output = pDeviceSettingsCombo->Output; pDeviceSettings->d3d11.sd.Windowed = pDeviceSettingsCombo->Windowed; if( GetSystemMetrics(SM_REMOTESESSION) != 0 ) { pDeviceSettings->d3d11.sd.Windowed = TRUE; } if (pDeviceSettingsCombo->pOutputInfo) { auto bestDisplayMode = pDeviceSettingsCombo->pOutputInfo->displayModeList[ bestModeIndex ]; if (!pDeviceSettingsCombo->Windowed) { pDeviceSettings->d3d11.sd.BufferDesc.Height = bestDisplayMode.Height; pDeviceSettings->d3d11.sd.BufferDesc.Width = bestDisplayMode.Width; pDeviceSettings->d3d11.sd.BufferDesc.RefreshRate.Numerator = bestDisplayMode.RefreshRate.Numerator; pDeviceSettings->d3d11.sd.BufferDesc.RefreshRate.Denominator = bestDisplayMode.RefreshRate.Denominator; pDeviceSettings->d3d11.sd.BufferDesc.Scaling = bestDisplayMode.Scaling; pDeviceSettings->d3d11.sd.BufferDesc.ScanlineOrdering = bestDisplayMode.ScanlineOrdering; } } if (pDeviceSettings->d3d11.DeviceFeatureLevel == 0) pDeviceSettings->d3d11.DeviceFeatureLevel = pDeviceSettingsCombo->pDeviceInfo->SelectedLevel; if ( pDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_WARP ) { D3D_FEATURE_LEVEL maxWarpFL = pEnum->GetWARPFeaturevel(); if ( pDeviceSettings->d3d11.DeviceFeatureLevel > maxWarpFL ) pDeviceSettings->d3d11.DeviceFeatureLevel = maxWarpFL; } if ( pDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE ) { D3D_FEATURE_LEVEL maxRefFL = pEnum->GetREFFeaturevel(); if ( pDeviceSettings->d3d11.DeviceFeatureLevel > maxRefFL ) pDeviceSettings->d3d11.DeviceFeatureLevel = maxRefFL; } pDeviceSettings->d3d11.sd.SampleDesc.Count = pDeviceSettingsCombo->multiSampleCountList[ bestMSAAIndex ]; if (pDeviceSettings->d3d11.sd.SampleDesc.Quality > pDeviceSettingsCombo->multiSampleQualityList[ bestMSAAIndex ] - 1) pDeviceSettings->d3d11.sd.SampleDesc.Quality = pDeviceSettingsCombo->multiSampleQualityList[ bestMSAAIndex ] - 1; pDeviceSettings->d3d11.sd.BufferDesc.Format = pDeviceSettingsCombo->BackBufferFormat; return S_OK; }