diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 232 |
1 files changed, 186 insertions, 46 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp index 0b48b54334..d3ed35b3c6 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -11,7 +11,11 @@ #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 { @@ -20,12 +24,74 @@ 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 = {}; - bool swapChainSizeSpecified = false; HRESULT result = S_OK; // IPropertySet is an optional parameter and can be null. @@ -34,12 +100,40 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert if (propertySet) { result = props.As(&mPropertyMap); - if (SUCCEEDED(result)) + 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) { - // 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, &swapChainSizeSpecified); + ERR("It is invalid to specify both an EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty."); + return false; } } @@ -48,6 +142,18 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert 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 @@ -57,16 +163,24 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert // 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 (swapChainSizeSpecified) + if (mSwapChainSizeSpecified) { mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; - - // Enable host swapchain scaling - mRequiresSwapChainScaling = true; } else { - result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect, &mRequiresSwapChainScaling); + SIZE swapChainPanelSize; + result = GetSwapChainPanelSize(mSwapChainPanel, mSwapChainPanelDispatcher, + &swapChainPanelSize, &mSwapChainScale); + if (mSwapChainScale != 1.0f) + mSwapChainScaleSpecified = true; + + if (SUCCEEDED(result)) + { + // Update the client rect to account for any swapchain scale factor + mClientRect = { 0, 0, static_cast<long>(ConvertDipsToPixels(swapChainPanelSize.cx * mSwapChainScale)), + static_cast<long>(ConvertDipsToPixels(swapChainPanelSize.cy * mSwapChainScale)) }; + } } } @@ -82,8 +196,8 @@ bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropert bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() { - ComPtr<ABI::Windows::UI::Xaml::ISizeChangedEventHandler> sizeChangedHandler; - ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement; + ComPtr<ISizeChangedEventHandler> sizeChangedHandler; + ComPtr<IFrameworkElement> frameworkElement; HRESULT result = Microsoft::WRL::MakeAndInitialize<SwapChainPanelSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); if (SUCCEEDED(result)) @@ -93,7 +207,13 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() if (SUCCEEDED(result)) { - result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + result = RunOnUIThread( + [this, frameworkElement, sizeChangedHandler] + { + return frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), + &mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); } if (SUCCEEDED(result)) @@ -106,16 +226,27 @@ bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() { - ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement; - if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + ComPtr<IFrameworkElement> frameworkElement; + if (mSwapChainPanel && SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) { - (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + RunOnUIThread( + [this, frameworkElement] + { + return frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + }, + mSwapChainPanelDispatcher); } mSizeChangedEventToken.value = 0; } -HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, + DXGIFactory *factory, + DXGI_FORMAT format, + unsigned int width, + unsigned int height, + bool containsAlpha, + DXGISwapChain **swapChain) { if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) { @@ -129,11 +260,13 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + 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 = DXGI_ALPHA_MODE_IGNORE; + swapChainDesc.AlphaMode = + containsAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; *swapChain = nullptr; @@ -149,7 +282,12 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa if (SUCCEEDED(result)) { - result = swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + result = RunOnUIThread( + [swapChainPanelNative, newSwapChain] + { + return swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + }, + mSwapChainPanelDispatcher); } if (SUCCEEDED(result)) @@ -164,34 +302,28 @@ HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFa // 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) && mRequiresSwapChainScaling) - { - ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement; - result = mSwapChainPanel.As(&uiElement); - ASSERT(SUCCEEDED(result)); - - Size currentSize; - result = uiElement->get_RenderSize(¤tSize); - ASSERT(SUCCEEDED(result)); - result = scaleSwapChain(currentSize); - } - if (SUCCEEDED(result)) { - // If automatic swapchain resize behaviors have been disabled, then - // unregister for the resize change events. - if (mSupportsSwapChainResize == false) + if (mSwapChainSizeSpecified || mSwapChainScaleSpecified) { - unregisterForSizeChangeEvents(); + ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement; + result = mSwapChainPanel.As(&uiElement); + ASSERT(SUCCEEDED(result)); + + Size currentSize; + result = uiElement->get_RenderSize(¤tSize); + ASSERT(SUCCEEDED(result)); + result = scaleSwapChain(currentSize, mClientRect); } } return result; } -HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize) +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &windowSize, const RECT &clientRect) { - ABI::Windows::Foundation::Size renderScale = { newSize.Width / mNewClientRect.right, newSize.Height / mNewClientRect.bottom }; + Size renderScale = {windowSize.Width / clientRect.right, + windowSize.Height / clientRect.bottom}; // Setup a scale matrix for the swap chain DXGI_MATRIX_3X2_F scaleMatrix = {}; scaleMatrix._11 = renderScale.Width; @@ -207,25 +339,33 @@ HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const Size &newSize) return result; } -HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize, bool *scalingActive) +HRESULT GetSwapChainPanelSize( + const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, + const ComPtr<ICoreDispatcher> &dispatcher, + SIZE *windowSize, float *scaleFactor) { - ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement; - ABI::Windows::Foundation::Size renderSize = { 0, 0 }; + ComPtr<IUIElement> uiElement; + Size renderSize = {0, 0}; HRESULT result = swapChainPanel.As(&uiElement); if (SUCCEEDED(result)) { - result = uiElement->get_RenderSize(&renderSize); + result = RunOnUIThread( + [uiElement, &renderSize] + { + return uiElement->get_RenderSize(&renderSize); + }, + dispatcher); } if (SUCCEEDED(result)) { long width = ConvertDipsToPixels(renderSize.Width); long height = ConvertDipsToPixels(renderSize.Height); - *windowSize = { 0, 0, width, height }; + *windowSize = { width, height }; - if (scalingActive) + if (scaleFactor) { - *scalingActive = width != renderSize.Width || height != renderSize.Height; + *scaleFactor = renderSize.Width / width; } } |