4481 lines
189 KiB
C++
4481 lines
189 KiB
C++
//--------------------------------------------------------------------------------------
|
|
// 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 <dxgidebug.h>
|
|
#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<DXUT_TIMER>* 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<DXUT_TIMER>*, 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<LONG>( GetDXUTState().GetWindowBackBufferWidthAtModeChange() ), static_cast<LONG>( GetDXUTState().GetWindowBackBufferHeightAtModeChange() ) }; return rc; }
|
|
RECT WINAPI DXUTGetFullsceenClientRectAtModeChange() { RECT rc = { 0, 0, static_cast<LONG>( GetDXUTState().GetFullScreenBackBufferWidthAtModeChange() ), static_cast<LONG>( 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<void**>( &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<KBDLLHOOKSTRUCT*>( 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<DXUT_TIMER>;
|
|
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;
|
|
}
|