diff options
Diffstat (limited to 'support/hololens/ServoApp/Common/DeviceResources.cpp')
-rw-r--r-- | support/hololens/ServoApp/Common/DeviceResources.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/support/hololens/ServoApp/Common/DeviceResources.cpp b/support/hololens/ServoApp/Common/DeviceResources.cpp new file mode 100644 index 00000000000..f5ffbec0d89 --- /dev/null +++ b/support/hololens/ServoApp/Common/DeviceResources.cpp @@ -0,0 +1,280 @@ + +#include "pch.h" +#include "DeviceResources.h" +#include "DirectXHelper.h" + +using namespace D2D1; +using namespace Microsoft::WRL; +using namespace winrt::Windows::Graphics::DirectX::Direct3D11; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Windows::Graphics::Holographic; + +// Constructor for DeviceResources. +DX::DeviceResources::DeviceResources() { CreateDeviceIndependentResources(); } + +// Configures resources that don't depend on the Direct3D device. +void DX::DeviceResources::CreateDeviceIndependentResources() { + // Initialize Direct2D resources. + D2D1_FACTORY_OPTIONS options{}; + +#if defined(_DEBUG) + // If the project is in a debug build, enable Direct2D debugging via SDK + // Layers. + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + // Initialize the Direct2D Factory. + winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory2), &options, + &m_d2dFactory)); + + // Initialize the DirectWrite Factory. + winrt::check_hresult(DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &m_dwriteFactory)); + + // Initialize the Windows Imaging Component (WIC) Factory. + winrt::check_hresult(CoCreateInstance(CLSID_WICImagingFactory2, nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&m_wicFactory))); +} + +void DX::DeviceResources::SetHolographicSpace( + HolographicSpace holographicSpace) { + // Cache the holographic space. Used to re-initalize during device-lost + // scenarios. + m_holographicSpace = holographicSpace; + + InitializeUsingHolographicSpace(); +} + +void DX::DeviceResources::InitializeUsingHolographicSpace() { + // The holographic space might need to determine which adapter supports + // holograms, in which case it will specify a non-zero PrimaryAdapterId. + LUID id = {m_holographicSpace.PrimaryAdapterId().LowPart, + m_holographicSpace.PrimaryAdapterId().HighPart}; + + // When a primary adapter ID is given to the app, the app should find + // the corresponding DXGI adapter and use it to create Direct3D devices + // and device contexts. Otherwise, there is no restriction on the DXGI + // adapter the app can use. + if ((id.HighPart != 0) || (id.LowPart != 0)) { + UINT createFlags = 0; +#ifdef DEBUG + if (DX::SdkLayersAvailable()) { + createFlags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + // Create the DXGI factory. + ComPtr<IDXGIFactory1> dxgiFactory; + winrt::check_hresult( + CreateDXGIFactory2(createFlags, IID_PPV_ARGS(&dxgiFactory))); + ComPtr<IDXGIFactory4> dxgiFactory4; + winrt::check_hresult(dxgiFactory.As(&dxgiFactory4)); + + // Retrieve the adapter specified by the holographic space. + winrt::check_hresult( + dxgiFactory4->EnumAdapterByLuid(id, IID_PPV_ARGS(&m_dxgiAdapter))); + } else { + m_dxgiAdapter.Reset(); + } + + CreateDeviceResources(); + + m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); +} + +// Configures the Direct3D device, and stores handles to it and the device +// context. +void DX::DeviceResources::CreateDeviceResources() { + // This flag adds support for surfaces with a different color channel ordering + // than the API default. It is required for compatibility with Direct2D. + UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#if defined(_DEBUG) + if (DX::SdkLayersAvailable()) { + // If the project is in a debug build, enable debugging via SDK Layers with + // this flag. + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + } +#endif + + // This array defines the set of DirectX hardware feature levels this app will + // support. Note the ordering should be preserved. Note that HoloLens supports + // feature level 11.1. The HoloLens emulator is also capable of running on + // graphics cards starting with feature level 10.0. + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}; + + // Create the Direct3D 11 API device object and a corresponding context. + ComPtr<ID3D11Device> device; + ComPtr<ID3D11DeviceContext> context; + + const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr + ? D3D_DRIVER_TYPE_HARDWARE + : D3D_DRIVER_TYPE_UNKNOWN; + const HRESULT hr = D3D11CreateDevice( + m_dxgiAdapter.Get(), // Either nullptr, or the primary adapter determined + // by Windows Holographic. + driverType, // Create a device using the hardware graphics driver. + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creationFlags, // Set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), // Size of the list above. + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows + // Runtime apps. + &device, // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + &context // Returns the device immediate context. + ); + + if (FAILED(hr)) { + // If the initialization fails, fall back to the WARP device. + // For more information on WARP, see: + // http://go.microsoft.com/fwlink/?LinkId=286690 + winrt::check_hresult(D3D11CreateDevice( + nullptr, // Use the default DXGI adapter for WARP. + D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware + // device. + 0, creationFlags, featureLevels, ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, &device, &m_d3dFeatureLevel, &context)); + } + + // Store pointers to the Direct3D device and immediate context. + winrt::check_hresult(device.As(&m_d3dDevice)); + winrt::check_hresult(context.As(&m_d3dContext)); + + // Acquire the DXGI interface for the Direct3D device. + ComPtr<IDXGIDevice3> dxgiDevice; + winrt::check_hresult(m_d3dDevice.As(&dxgiDevice)); + + // Wrap the native device using a WinRT interop object. + winrt::com_ptr<::IInspectable> object; + winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice( + dxgiDevice.Get(), + reinterpret_cast<IInspectable **>(winrt::put_abi(object)))); + m_d3dInteropDevice = object.as<IDirect3DDevice>(); + + // Cache the DXGI adapter. + // This is for the case of no preferred DXGI adapter, or fallback to WARP. + ComPtr<IDXGIAdapter> dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(&dxgiAdapter)); + winrt::check_hresult(dxgiAdapter.As(&m_dxgiAdapter)); + + // Check for device support for the optional feature that allows setting the + // render target array index from the vertex shader stage. + D3D11_FEATURE_DATA_D3D11_OPTIONS3 options; + m_d3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &options, + sizeof(options)); + if (options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer) { + m_supportsVprt = true; + } +} + +// Validates the back buffer for each HolographicCamera and recreates +// resources for back buffers that have changed. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::EnsureCameraResources( + HolographicFrame frame, HolographicFramePrediction prediction) { + UseHolographicCameraResources<void>( + [this, frame, + prediction](std::map<UINT32, std::unique_ptr<CameraResources>> + &cameraResourceMap) { + for (HolographicCameraPose const &cameraPose : + prediction.CameraPoses()) { + HolographicCameraRenderingParameters renderingParameters = + frame.GetRenderingParameters(cameraPose); + CameraResources *pCameraResources = + cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + + pCameraResources->CreateResourcesForBackBuffer(this, + renderingParameters); + } + }); +} + +// Prepares to allocate resources and adds resource views for a camera. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::AddHolographicCamera(HolographicCamera camera) { + UseHolographicCameraResources<void>( + [this, camera](std::map<UINT32, std::unique_ptr<CameraResources>> + &cameraResourceMap) { + cameraResourceMap[camera.Id()] = + std::make_unique<CameraResources>(camera); + }); +} + +// Deallocates resources for a camera and removes the camera from the set. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::RemoveHolographicCamera(HolographicCamera camera) { + UseHolographicCameraResources<void>( + [this, camera](std::map<UINT32, std::unique_ptr<CameraResources>> + &cameraResourceMap) { + CameraResources *pCameraResources = + cameraResourceMap[camera.Id()].get(); + + if (pCameraResources != nullptr) { + pCameraResources->ReleaseResourcesForBackBuffer(this); + cameraResourceMap.erase(camera.Id()); + } + }); +} + +// Recreate all device resources and set them back to the current state. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::HandleDeviceLost() { + if (m_deviceNotify != nullptr) { + m_deviceNotify->OnDeviceLost(); + } + + UseHolographicCameraResources<void>( + [this](std::map<UINT32, std::unique_ptr<CameraResources>> + &cameraResourceMap) { + for (auto &pair : cameraResourceMap) { + CameraResources *pCameraResources = pair.second.get(); + pCameraResources->ReleaseResourcesForBackBuffer(this); + } + }); + + InitializeUsingHolographicSpace(); + + if (m_deviceNotify != nullptr) { + m_deviceNotify->OnDeviceRestored(); + } +} + +// Register our DeviceNotify to be informed on device lost and creation. +void DX::DeviceResources::RegisterDeviceNotify( + DX::IDeviceNotify *deviceNotify) { + m_deviceNotify = deviceNotify; +} + +// Call this method when the app suspends. It provides a hint to the driver that +// the app is entering an idle state and that temporary buffers can be reclaimed +// for use by other apps. +void DX::DeviceResources::Trim() { + m_d3dContext->ClearState(); + + ComPtr<IDXGIDevice3> dxgiDevice; + winrt::check_hresult(m_d3dDevice.As(&dxgiDevice)); + dxgiDevice->Trim(); +} + +// Present the contents of the swap chain to the screen. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::Present(HolographicFrame frame) { + // By default, this API waits for the frame to finish before it returns. + // Holographic apps should wait for the previous frame to finish before + // starting work on a new frame. This allows for better results from + // holographic frame predictions. + HolographicFramePresentResult presentResult = + frame.PresentUsingCurrentPrediction(); + + // The PresentUsingCurrentPrediction API will detect when the graphics device + // changes or becomes invalid. When this happens, it is considered a Direct3D + // device lost scenario. + if (presentResult == HolographicFramePresentResult::DeviceRemoved) { + // The Direct3D device, context, and resources should be recreated. + HandleDeviceLost(); + } +} |