From e1bf674c16e3c8472b29574159c789cd3f0c64e0 Mon Sep 17 00:00:00 2001 From: Bryan Galdrikian Date: Fri, 24 Feb 2017 09:32:20 -0800 Subject: Updating to blast_source-windows@1.0.347-21749006 and blast_tools_and_samples-windows@1.0.347-21749006 with a new directory structure. NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this. --- samples/SampleBase/core/DeviceManager.cpp | 795 ++++++++++++++++++++++++++++++ 1 file changed, 795 insertions(+) create mode 100644 samples/SampleBase/core/DeviceManager.cpp (limited to 'samples/SampleBase/core/DeviceManager.cpp') diff --git a/samples/SampleBase/core/DeviceManager.cpp b/samples/SampleBase/core/DeviceManager.cpp new file mode 100644 index 0000000..26f9fbb --- /dev/null +++ b/samples/SampleBase/core/DeviceManager.cpp @@ -0,0 +1,795 @@ +// TAGRELEASE: PUBLIC + +#include "DeviceManager.h" +#include +#include +#include +#include +#include +#include "SampleProfiler.h" + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } +#endif + +#define WINDOW_CLASS_NAME L"NvDX11" + +#define WINDOW_STYLE_NORMAL (WS_OVERLAPPEDWINDOW | WS_VISIBLE) +#define WINDOW_STYLE_FULLSCREEN (WS_POPUP | WS_SYSMENU | WS_VISIBLE) + +// A singleton, sort of... To pass the events from WindowProc to the object. +DeviceManager* g_DeviceManagerInstance = NULL; + +#undef min +#undef max + +LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if(g_DeviceManagerInstance) + return g_DeviceManagerInstance->MsgProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +DeviceManager* GetDeviceManager() +{ + return g_DeviceManagerInstance; +} + +namespace +{ + bool IsNvDeviceID(UINT id) + { + return id == 0x10DE; + } + + // Find an adapter whose name contains the given string. + IDXGIAdapter* FindAdapter(const WCHAR* targetName, bool& isNv) + { + IDXGIAdapter* targetAdapter = NULL; + IDXGIFactory* IDXGIFactory_0001 = NULL; + HRESULT hres = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&IDXGIFactory_0001); + if (hres != S_OK) + { + printf("ERROR in CreateDXGIFactory, %s@%d.\nFor more info, get log from debug D3D runtime: (1) Install DX SDK, and enable Debug D3D from DX Control Panel Utility. (2) Install and start DbgView. (3) Try running the program again.\n",__FILE__,__LINE__); + return targetAdapter; + } + + unsigned int adapterNo = 0; + while (SUCCEEDED(hres)) + { + IDXGIAdapter* pAdapter = NULL; + hres = IDXGIFactory_0001->EnumAdapters(adapterNo, (IDXGIAdapter**)&pAdapter); + + if (SUCCEEDED(hres)) + { + DXGI_ADAPTER_DESC aDesc; + pAdapter->GetDesc(&aDesc); + + // If no name is specified, return the first adapater. This is the same behaviour as the + // default specified for D3D11CreateDevice when no adapter is specified. + if (wcslen(targetName) == 0) + { + targetAdapter = pAdapter; + isNv = IsNvDeviceID(aDesc.VendorId); + break; + } + + std::wstring aName = aDesc.Description; + if (aName.find(targetName) != std::string::npos) + { + targetAdapter = pAdapter; + isNv = IsNvDeviceID(aDesc.VendorId); + } + else + { + pAdapter->Release(); + } + } + + adapterNo++; + } + + if (IDXGIFactory_0001) + IDXGIFactory_0001->Release(); + + return targetAdapter; + } + + // Adjust window rect so that it is centred on the given adapter. Clamps to fit if it's too big. + RECT MoveWindowOntoAdapter(IDXGIAdapter* targetAdapter, const RECT& rect) + { + assert(targetAdapter != NULL); + + RECT result = rect; + HRESULT hres = S_OK; + unsigned int outputNo = 0; + while (SUCCEEDED(hres)) + { + IDXGIOutput* pOutput = NULL; + hres = targetAdapter->EnumOutputs(outputNo++, &pOutput); + + if (SUCCEEDED(hres) && pOutput) + { + DXGI_OUTPUT_DESC OutputDesc; + pOutput->GetDesc( &OutputDesc ); + const RECT desktop = OutputDesc.DesktopCoordinates; + const int centreX = (int) desktop.left + (int)(desktop.right - desktop.left) / 2; + const int centreY = (int) desktop.top + (int)(desktop.bottom - desktop.top) / 2; + const int winW = rect.right - rect.left; + const int winH = rect.bottom - rect.top; + int left = centreX - winW/2; + int right = left + winW; + int top = centreY - winH/2; + int bottom = top + winH; + result.left = std::max(left, (int) desktop.left); + result.right = std::min(right, (int) desktop.right); + result.bottom = std::min(bottom, (int) desktop.bottom); + result.top = std::max(top, (int) desktop.top); + pOutput->Release(); + + // If there is more than one output, go with the first found. Multi-monitor support could go here. + break; + } + } + return result; + } +} + +HRESULT +DeviceManager::CreateWindowDeviceAndSwapChain(const DeviceCreationParameters& params, std::wstring title) +{ + g_DeviceManagerInstance = this; + m_WindowTitle = title; + + HINSTANCE hInstance = GetModuleHandle(NULL); + WNDCLASSEX windowClass = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WindowProc, + 0L, 0L, hInstance, NULL, NULL, NULL, NULL, WINDOW_CLASS_NAME, NULL }; + + windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); + + RegisterClassEx(&windowClass); + + UINT windowStyle = params.startFullscreen + ? WINDOW_STYLE_FULLSCREEN + : params.startMaximized + ? (WINDOW_STYLE_NORMAL | WS_MAXIMIZE) + : WINDOW_STYLE_NORMAL; + + RECT rect = { 0, 0, params.backBufferWidth, params.backBufferHeight }; + AdjustWindowRect(&rect, windowStyle, FALSE); + + IDXGIAdapter* targetAdapter = FindAdapter(params.adapterNameSubstring, m_IsNvidia); + if (targetAdapter) + { + rect = MoveWindowOntoAdapter(targetAdapter, rect); + } + else + { + // We could silently use a default adapter in this case. I think it's better to choke. + std::wostringstream ostr; + ostr << L"Could not find an adapter matching \"" << params.adapterNameSubstring << "\"" << std::ends; + MessageBox(NULL, ostr.str().c_str(), m_WindowTitle.c_str(), MB_OK | MB_ICONERROR); + return E_FAIL; + } + + m_hWnd = CreateWindowEx( + 0, + WINDOW_CLASS_NAME, + title.c_str(), + windowStyle, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + GetDesktopWindow(), + NULL, + hInstance, + NULL + ); + + if(!m_hWnd) + { +#ifdef DEBUG + DWORD errorCode = GetLastError(); + printf("CreateWindowEx error code = 0x%x\n", errorCode); +#endif + + MessageBox(NULL, L"Cannot create window", m_WindowTitle.c_str(), MB_OK | MB_ICONERROR); + return E_FAIL; + } + + UpdateWindow(m_hWnd); + + HRESULT hr = E_FAIL; + + RECT clientRect; + GetClientRect(m_hWnd, &clientRect); + UINT width = clientRect.right - clientRect.left; + UINT height = clientRect.bottom - clientRect.top; + + ZeroMemory(&m_SwapChainDesc, sizeof(m_SwapChainDesc)); + m_SwapChainDesc.BufferCount = params.swapChainBufferCount; + m_SwapChainDesc.BufferDesc.Width = width; + m_SwapChainDesc.BufferDesc.Height = height; + m_SwapChainDesc.BufferDesc.Format = params.swapChainFormat; + m_SwapChainDesc.BufferDesc.RefreshRate.Numerator = params.refreshRate; + m_SwapChainDesc.BufferDesc.RefreshRate.Denominator = 0; + m_SwapChainDesc.BufferUsage = params.swapChainUsage; + m_SwapChainDesc.OutputWindow = m_hWnd; + m_SwapChainDesc.SampleDesc.Count = params.swapChainSampleCount; + m_SwapChainDesc.SampleDesc.Quality = params.swapChainSampleQuality; + m_SwapChainDesc.Windowed = !params.startFullscreen; + m_SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + // The D3D documentation says that if adapter is non-null, driver type must be unknown. Why not put + // this logic in the CreateDevice fns then?!? + const D3D_DRIVER_TYPE dType = (targetAdapter)? D3D_DRIVER_TYPE_UNKNOWN: params.driverType; + + hr = D3D11CreateDeviceAndSwapChain( + targetAdapter, // pAdapter + dType, // DriverType + NULL, // Software + params.createDeviceFlags, // Flags + ¶ms.featureLevel, // pFeatureLevels + 1, // FeatureLevels + D3D11_SDK_VERSION, // SDKVersion + &m_SwapChainDesc, // pSwapChainDesc + &m_SwapChain, // ppSwapChain + &m_Device, // ppDevice + NULL, // pFeatureLevel + &m_ImmediateContext // ppImmediateContext + ); + + if (targetAdapter) + targetAdapter->Release(); + + if(FAILED(hr)) + return hr; + + m_DepthStencilDesc.ArraySize = 1; + m_DepthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + m_DepthStencilDesc.CPUAccessFlags = 0; + m_DepthStencilDesc.Format = params.depthStencilFormat; + m_DepthStencilDesc.Width = width; + m_DepthStencilDesc.Height = height; + m_DepthStencilDesc.MipLevels = 1; + m_DepthStencilDesc.MiscFlags = 0; + m_DepthStencilDesc.SampleDesc.Count = params.swapChainSampleCount; + m_DepthStencilDesc.SampleDesc.Quality = 0; + m_DepthStencilDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = CreateRenderTargetAndDepthStencil(); + + if(FAILED(hr)) + return hr; + + DeviceCreated(); + BackBufferResized(); + + return S_OK; +} + +void +DeviceManager::Shutdown() +{ + if(m_SwapChain && GetWindowState() == kWindowFullscreen) + m_SwapChain->SetFullscreenState(false, NULL); + + DeviceDestroyed(); + + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_DepthStencilDSV); + SAFE_RELEASE(m_DepthStencilBuffer); + + g_DeviceManagerInstance = NULL; + SAFE_RELEASE(m_ImmediateContext); + SAFE_RELEASE(m_SwapChain); + + ID3D11Debug * d3dDebug = nullptr; + if (nullptr != m_Device) + { + ID3D11DeviceContext* pCtx; + m_Device->GetImmediateContext(&pCtx); + pCtx->ClearState(); + pCtx->Flush(); + pCtx->Release(); + if (SUCCEEDED(m_Device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast(&d3dDebug)))) + { + d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); + d3dDebug->Release(); + } + } + SAFE_RELEASE(m_Device); + + if(m_hWnd) + { + DestroyWindow(m_hWnd); + m_hWnd = NULL; + } +} + +HRESULT +DeviceManager::CreateRenderTargetAndDepthStencil() +{ + HRESULT hr; + + ID3D11Texture2D *backBuffer = NULL; + hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer); + if (FAILED(hr)) + return hr; + + hr = m_Device->CreateRenderTargetView(backBuffer, NULL, &m_BackBufferRTV); + backBuffer->Release(); + if (FAILED(hr)) + return hr; + + if(m_DepthStencilDesc.Format != DXGI_FORMAT_UNKNOWN) + { + hr = m_Device->CreateTexture2D(&m_DepthStencilDesc, NULL, &m_DepthStencilBuffer); + if (FAILED(hr)) + return hr; + + hr = m_Device->CreateDepthStencilView(m_DepthStencilBuffer, NULL, &m_DepthStencilDSV); + if (FAILED(hr)) + return hr; + } + + return S_OK; +} + +void +DeviceManager::MessageLoop() +{ + MSG msg = {0}; + + LARGE_INTEGER perfFreq, previousTime; + QueryPerformanceFrequency(&perfFreq); + QueryPerformanceCounter(&previousTime); + + while (WM_QUIT != msg.message) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + PROFILER_BEGIN("Main Loop"); + + LARGE_INTEGER newTime; + QueryPerformanceCounter(&newTime); + + double elapsedSeconds = (m_FixedFrameInterval >= 0) + ? m_FixedFrameInterval + : (double)(newTime.QuadPart - previousTime.QuadPart) / (double)perfFreq.QuadPart; + + if(m_SwapChain && GetWindowState() != kWindowMinimized) + { + Animate(elapsedSeconds); + Render(); + m_SwapChain->Present(m_SyncInterval, 0); + Sleep(0); + } + else + { + // Release CPU resources when idle + Sleep(1); + } + + { + m_vFrameTimes.push_back(elapsedSeconds); + double timeSum = 0; + for(auto it = m_vFrameTimes.begin(); it != m_vFrameTimes.end(); it++) + timeSum += *it; + + if(timeSum > m_AverageTimeUpdateInterval) + { + m_AverageFrameTime = timeSum / (double)m_vFrameTimes.size(); + m_vFrameTimes.clear(); + } + } + + previousTime = newTime; + + PROFILER_END(); + PROFILER_RESET(); + } + + } +} + +LRESULT +DeviceManager::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: + case WM_CLOSE: + PostQuitMessage(0); + return 0; + + case WM_SYSKEYDOWN: + if(wParam == VK_F4) + { + PostQuitMessage(0); + return 0; + } + break; + + case WM_ENTERSIZEMOVE: + m_InSizingModalLoop = true; + m_NewWindowSize.cx = m_SwapChainDesc.BufferDesc.Width; + m_NewWindowSize.cy = m_SwapChainDesc.BufferDesc.Height; + break; + + case WM_EXITSIZEMOVE: + m_InSizingModalLoop = false; + ResizeSwapChain(); + break; + + case WM_SIZE: + // Ignore the WM_SIZE event if there is no device, + // or if the window has been minimized (size == 0), + // or if it has been restored to the previous size (this part is tested inside ResizeSwapChain) + if (m_Device && (lParam != 0)) + { + m_NewWindowSize.cx = LOWORD(lParam); + m_NewWindowSize.cy = HIWORD(lParam); + + if(!m_InSizingModalLoop) + ResizeSwapChain(); + } + } + + if( uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST || + uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST ) + { + // processing messages front-to-back + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + if((*it)->IsEnabled()) + { + // for kb/mouse messages, 0 means the message has been handled + if(0 == (*it)->MsgProc(hWnd, uMsg, wParam, lParam)) + return 0; + } + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void +DeviceManager::ResizeSwapChain() +{ + if(m_NewWindowSize.cx == (LONG)m_SwapChainDesc.BufferDesc.Width && + m_NewWindowSize.cy == (LONG)m_SwapChainDesc.BufferDesc.Height) + return; + + m_SwapChainDesc.BufferDesc.Width = m_NewWindowSize.cx; + m_SwapChainDesc.BufferDesc.Height = m_NewWindowSize.cy; + + ID3D11RenderTargetView *nullRTV = NULL; + m_ImmediateContext->OMSetRenderTargets(1, &nullRTV, NULL); + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_DepthStencilDSV); + SAFE_RELEASE(m_DepthStencilBuffer); + + if (m_SwapChain) + { + // Resize the swap chain + m_SwapChain->ResizeBuffers(m_SwapChainDesc.BufferCount, m_SwapChainDesc.BufferDesc.Width, + m_SwapChainDesc.BufferDesc.Height, m_SwapChainDesc.BufferDesc.Format, + m_SwapChainDesc.Flags); + + m_DepthStencilDesc.Width = m_NewWindowSize.cx; + m_DepthStencilDesc.Height = m_NewWindowSize.cy; + + CreateRenderTargetAndDepthStencil(); + + BackBufferResized(); + } +} + +void +DeviceManager::Render() +{ + PROFILER_SCOPED_FUNCTION(); + + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (float)m_SwapChainDesc.BufferDesc.Width, (float)m_SwapChainDesc.BufferDesc.Height, 0.0f, 1.0f }; + + // rendering back-to-front + for(auto it = m_vControllers.rbegin(); it != m_vControllers.rend(); it++) + { + if((*it)->IsEnabled()) + { + m_ImmediateContext->OMSetRenderTargets(1, &m_BackBufferRTV, m_DepthStencilDSV); + m_ImmediateContext->RSSetViewports(1, &viewport); + + (*it)->Render(m_Device, m_ImmediateContext, m_BackBufferRTV, m_DepthStencilDSV); + } + } + + m_ImmediateContext->OMSetRenderTargets(0, NULL, NULL); +} + +void +DeviceManager::Animate(double fElapsedTimeSeconds) +{ + PROFILER_SCOPED_FUNCTION(); + + // front-to-back, but the order shouldn't matter + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + if((*it)->IsEnabled()) + { + (*it)->Animate(fElapsedTimeSeconds); + } + } +} + +void +DeviceManager::DeviceCreated() +{ + // creating resources front-to-back + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + (*it)->DeviceCreated(m_Device); + } +} + +void +DeviceManager::DeviceDestroyed() +{ + // releasing resources back-to-front + for(auto it = m_vControllers.rbegin(); it != m_vControllers.rend(); it++) + { + (*it)->DeviceDestroyed(); + } +} + +void +DeviceManager::BackBufferResized() +{ + if(m_SwapChain == NULL) + return; + + DXGI_SURFACE_DESC backSD; + backSD.Format = m_SwapChainDesc.BufferDesc.Format; + backSD.Width = m_SwapChainDesc.BufferDesc.Width; + backSD.Height = m_SwapChainDesc.BufferDesc.Height; + backSD.SampleDesc = m_SwapChainDesc.SampleDesc; + + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + (*it)->BackBufferResized(m_Device, &backSD); + } +} + +HRESULT +DeviceManager::ChangeBackBufferFormat(DXGI_FORMAT format, UINT sampleCount) +{ + HRESULT hr = E_FAIL; + + if((format == DXGI_FORMAT_UNKNOWN || format == m_SwapChainDesc.BufferDesc.Format) && + (sampleCount == 0 || sampleCount == m_SwapChainDesc.SampleDesc.Count)) + return S_FALSE; + + if(m_Device) + { + bool fullscreen = (GetWindowState() == kWindowFullscreen); + if(fullscreen) + m_SwapChain->SetFullscreenState(false, NULL); + + IDXGISwapChain* newSwapChain = NULL; + DXGI_SWAP_CHAIN_DESC newSwapChainDesc = m_SwapChainDesc; + + if(format != DXGI_FORMAT_UNKNOWN) + newSwapChainDesc.BufferDesc.Format = format; + if(sampleCount != 0) + newSwapChainDesc.SampleDesc.Count = sampleCount; + + IDXGIAdapter* pDXGIAdapter = GetDXGIAdapter(); + + IDXGIFactory* pDXGIFactory = NULL; + pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast(&pDXGIFactory)); + + hr = pDXGIFactory->CreateSwapChain(m_Device, &newSwapChainDesc, &newSwapChain); + + pDXGIFactory->Release(); + pDXGIAdapter->Release(); + + if (FAILED(hr)) + { + if(fullscreen) + m_SwapChain->SetFullscreenState(true, NULL); + + return hr; + } + + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_SwapChain); + SAFE_RELEASE(m_DepthStencilBuffer); + SAFE_RELEASE(m_DepthStencilDSV); + + m_SwapChain = newSwapChain; + m_SwapChainDesc = newSwapChainDesc; + + m_DepthStencilDesc.SampleDesc.Count = sampleCount; + + if(fullscreen) + m_SwapChain->SetFullscreenState(true, NULL); + + CreateRenderTargetAndDepthStencil(); + BackBufferResized(); + } + + return S_OK; +} + +void +DeviceManager::AddControllerToFront(IVisualController* pController) +{ + m_vControllers.remove(pController); + m_vControllers.push_front(pController); +} + +void +DeviceManager::AddControllerToBack(IVisualController* pController) +{ + m_vControllers.remove(pController); + m_vControllers.push_back(pController); +} + +void +DeviceManager::RemoveController(IVisualController* pController) +{ + m_vControllers.remove(pController); +} + +HRESULT +DeviceManager::ResizeWindow(int width, int height) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + RECT rect; + GetWindowRect(m_hWnd, &rect); + + ShowWindow(m_hWnd, SW_RESTORE); + + if(!MoveWindow(m_hWnd, rect.left, rect.top, width, height, true)) + return E_FAIL; + + // No need to call m_SwapChain->ResizeBackBuffer because MoveWindow will send WM_SIZE, which calls that function. + + return S_OK; +} + +HRESULT +DeviceManager::EnterFullscreenMode(int width, int height) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + if(GetWindowState() == kWindowFullscreen) + return S_FALSE; + + if(width <= 0 || height <= 0) + { + width = m_SwapChainDesc.BufferDesc.Width; + height = m_SwapChainDesc.BufferDesc.Height; + } + + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_FULLSCREEN); + MoveWindow(m_hWnd, 0, 0, width, height, true); + + HRESULT hr = m_SwapChain->SetFullscreenState(true, NULL); + + if(FAILED(hr)) + { + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_NORMAL); + return hr; + } + + UpdateWindow(m_hWnd); + m_SwapChain->GetDesc(&m_SwapChainDesc); + + return S_OK; +} + +HRESULT +DeviceManager::LeaveFullscreenMode(int windowWidth, int windowHeight) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + if(GetWindowState() != kWindowFullscreen) + return S_FALSE; + + HRESULT hr = m_SwapChain->SetFullscreenState(false, NULL); + if(FAILED(hr)) return hr; + + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_NORMAL); + + if(windowWidth <= 0 || windowHeight <= 0) + { + windowWidth = m_SwapChainDesc.BufferDesc.Width; + windowHeight = m_SwapChainDesc.BufferDesc.Height; + } + + RECT rect = { 0, 0, windowWidth, windowHeight }; + AdjustWindowRect(&rect, WINDOW_STYLE_NORMAL, FALSE); + MoveWindow(m_hWnd, 0, 0, rect.right - rect.left, rect.bottom - rect.top, true); + UpdateWindow(m_hWnd); + + m_SwapChain->GetDesc(&m_SwapChainDesc); + + return S_OK; +} + +HRESULT +DeviceManager::ToggleFullscreen() +{ + if(GetWindowState() == kWindowFullscreen) + return LeaveFullscreenMode(); + else + return EnterFullscreenMode(); +} + +DeviceManager::WindowState +DeviceManager::GetWindowState() +{ + if(m_SwapChain && !m_SwapChainDesc.Windowed) + return kWindowFullscreen; + + if(m_hWnd == INVALID_HANDLE_VALUE) + return kWindowNone; + + if(IsZoomed(m_hWnd)) + return kWindowMaximized; + + if(IsIconic(m_hWnd)) + return kWindowMinimized; + + return kWindowNormal; +} + +HRESULT +DeviceManager::GetDisplayResolution(int& width, int& height) +{ + if(m_hWnd != INVALID_HANDLE_VALUE) + { + HMONITOR monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + + if(GetMonitorInfo(monitor, &info)) + { + width = info.rcMonitor.right - info.rcMonitor.left; + height = info.rcMonitor.bottom - info.rcMonitor.top; + return S_OK; + } + } + + return E_FAIL; +} + +IDXGIAdapter* +DeviceManager::GetDXGIAdapter() +{ + if(!m_Device) + return NULL; + + IDXGIDevice* pDXGIDevice = NULL; + m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&pDXGIDevice)); + + IDXGIAdapter* pDXGIAdapter = NULL; + pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast(&pDXGIAdapter)); + + pDXGIDevice->Release(); + + return pDXGIAdapter; +} -- cgit v1.2.3