diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp new file mode 100755 index 000000000..1dae1ad7d --- /dev/null +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -0,0 +1,355 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +#include <algorithm> +#include <math.h> + +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::Xaml; +using namespace Microsoft::WRL; + +namespace rx +{ +SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +template <typename T> +struct AddFtmBase +{ + typedef Implements<RuntimeClassFlags<ClassicCom>, T, FtmBase> Type; +}; + +template <typename CODE> +HRESULT RunOnUIThread(CODE &&code, const ComPtr<ICoreDispatcher> &dispatcher) +{ + ComPtr<IAsyncAction> asyncAction; + HRESULT result = S_OK; + + boolean hasThreadAccess; + result = dispatcher->get_HasThreadAccess(&hasThreadAccess); + if (FAILED(result)) + { + return result; + } + + if (hasThreadAccess) + { + return code(); + } + else + { + Event waitEvent(CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS)); + if (!waitEvent.IsValid()) + { + return E_FAIL; + } + + HRESULT codeResult = E_FAIL; + auto handler = + Callback<AddFtmBase<IDispatchedHandler>::Type>([&codeResult, &code, &waitEvent] + { + codeResult = code(); + SetEvent(waitEvent.Get()); + return S_OK; + }); + + result = dispatcher->RunAsync(CoreDispatcherPriority_Normal, handler.Get(), + asyncAction.GetAddressOf()); + if (FAILED(result)) + { + return result; + } + + auto waitResult = WaitForSingleObjectEx(waitEvent.Get(), 10 * 1000, true); + if (waitResult != WAIT_OBJECT_0) + { + // Wait 10 seconds before giving up. At this point, the application is in an + // unrecoverable state (probably deadlocked). We therefore terminate the application + // entirely. This also prevents stack corruption if the async operation is eventually + // run. + ERR("Timeout waiting for async action on UI thread. The UI thread might be blocked."); + std::terminate(); + return E_FAIL; + } + + return codeResult; + } +} + +bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + ComPtr<IPropertySet> props = propertySet; + ComPtr<IInspectable> win = window; + SIZE swapChainSize = {}; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified); + if (FAILED(result)) + { + return false; + } + + // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified); + if (FAILED(result)) + { + return false; + } + + if (!mSwapChainScaleSpecified) + { + // Default value for the scale is 1.0f + mSwapChainScale = 1.0f; + } + + // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified + if (mSwapChainScaleSpecified && mSwapChainSizeSpecified) + { + ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + return false; + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mSwapChainPanel); + } + + ComPtr<IDependencyObject> swapChainPanelDependencyObject; + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelDependencyObject); + } + + if (SUCCEEDED(result)) + { + result = swapChainPanelDependencyObject->get_Dispatcher( + mSwapChainPanelDispatcher.GetAddressOf()); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output needs to be handled by the + // host for swapchain panels even though the scaling mode setting + // DXGI_SCALING_STRETCH is configured on the swapchain. + if (mSwapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + } + else + { + Size swapChainPanelSize; + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + &swapChainPanelSize); + + if (SUCCEEDED(result)) + { + // Update the client rect to account for any swapchain scale factor + mClientRect = clientRect(swapChainPanelSize); + } + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() +{ + ComPtr<ISizeChangedEventHandler> sizeChangedHandler; + ComPtr<IFrameworkElement> frameworkElement; + HRESULT result = Microsoft::WRL::MakeAndInitialize<SwapChainPanelSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&frameworkElement); + } + + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [this, frameworkElement, sizeChangedHandler] + { + return frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), + &mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() +{ + ComPtr<IFrameworkElement> frameworkElement; + if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + { + RunOnUIThread( + [this, frameworkElement] + { + return frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); + } + + mSizeChangedEventToken.value = 0; +} + +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, + IDXGIFactory2 *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + IDXGISwapChain1 **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = + DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = + containsAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; + + *swapChain = nullptr; + + ComPtr<IDXGISwapChain1> newSwapChain; + ComPtr<ISwapChainPanelNative> swapChainPanelNative; + Size currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelNative); + } + + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [swapChainPanelNative, newSwapChain] + { + return swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + }, + mSwapChainPanelDispatcher); + } + + if (SUCCEEDED(result)) + { + // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel + // to perform the runtime-scale behavior. This swapchain is cached here because there are + // no methods for retreiving the currently configured on from ISwapChainPanelNative. + mSwapChain = newSwapChain; + result = newSwapChain.CopyTo(swapChain); + } + + // If the host is responsible for scaling the output of the swapchain, then + // scale it now before returning an instance to the caller. This is done by + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result)) + { + if (mSwapChainSizeSpecified || mSwapChainScaleSpecified) + { + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + ¤tPanelSize); + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result)) + { + result = scaleSwapChain(currentPanelSize, mClientRect); + } + } + } + + return result; +} + +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect) +{ + Size renderScale = {windowSize.Width / (float)clientRect.right, + windowSize.Height / (float)clientRect.bottom}; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; + scaleMatrix._22 = renderScale.Height; + + ComPtr<IDXGISwapChain2> swapChain2; + HRESULT result = mSwapChain.As(&swapChain2); + if (SUCCEEDED(result)) + { + result = swapChain2->SetMatrixTransform(&scaleMatrix); + } + + return result; +} + +HRESULT GetSwapChainPanelSize( + const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, + const ComPtr<ICoreDispatcher> &dispatcher, + Size *windowSize) +{ + ComPtr<IUIElement> uiElement; + HRESULT result = swapChainPanel.As(&uiElement); + if (SUCCEEDED(result)) + { + result = RunOnUIThread( + [uiElement, windowSize] { return uiElement->get_RenderSize(windowSize); }, dispatcher); + } + + return result; +} +}
\ No newline at end of file |