1 //
2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types.
8 
9 #include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h"
10 
11 #include <windows.graphics.display.h>
12 
13 using namespace ABI::Windows::Foundation::Collections;
14 
15 namespace rx
16 {
~CoreWindowNativeWindow()17 CoreWindowNativeWindow::~CoreWindowNativeWindow()
18 {
19     unregisterForSizeChangeEvents();
20 }
21 
initialize(EGLNativeWindowType window,IPropertySet * propertySet)22 bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet)
23 {
24     ComPtr<IPropertySet> props = propertySet;
25     ComPtr<IInspectable> win = window;
26     SIZE swapChainSize = {};
27     HRESULT result = S_OK;
28 
29     // IPropertySet is an optional parameter and can be null.
30     // If one is specified, cache as an IMap and read the properties
31     // used for initial host initialization.
32     if (propertySet)
33     {
34         result = props.As(&mPropertyMap);
35         if (FAILED(result))
36         {
37             return false;
38         }
39 
40         // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
41         // was prevalidated to contain the EGLNativeWindowType before being passed to
42         // this host.
43         result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &mSwapChainSizeSpecified);
44         if (FAILED(result))
45         {
46             return false;
47         }
48 
49         // The EGLRenderResolutionScaleProperty is optional and may be missing. The IPropertySet
50         // was prevalidated to contain the EGLNativeWindowType before being passed to
51         // this host.
52         result = GetOptionalSinglePropertyValue(mPropertyMap, EGLRenderResolutionScaleProperty, &mSwapChainScale, &mSwapChainScaleSpecified);
53         if (FAILED(result))
54         {
55             return false;
56         }
57 
58         if (!mSwapChainScaleSpecified)
59         {
60             // Default value for the scale is 1.0f
61             mSwapChainScale = 1.0f;
62         }
63 
64         // A EGLRenderSurfaceSizeProperty and a EGLRenderResolutionScaleProperty can't both be specified
65         if (mSwapChainScaleSpecified && mSwapChainSizeSpecified)
66         {
67             ERR() << "It is invalid to specify both an EGLRenderSurfaceSizeProperty and a "
68                      "EGLRenderResolutionScaleProperty.";
69             return false;
70         }
71     }
72 
73     if (SUCCEEDED(result))
74     {
75         result = win.As(&mCoreWindow);
76     }
77 
78     if (SUCCEEDED(result))
79     {
80         // If a swapchain size is specfied, then the automatic resize
81         // behaviors implemented by the host should be disabled.  The swapchain
82         // will be still be scaled when being rendered to fit the bounds
83         // of the host.
84         // Scaling of the swapchain output occurs automatically because if
85         // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
86         if (mSwapChainSizeSpecified)
87         {
88             mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
89         }
90         else
91         {
92             Size coreWindowSize;
93             result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
94 
95             if (SUCCEEDED(result))
96             {
97                 mClientRect = clientRect(coreWindowSize);
98             }
99         }
100     }
101 
102     if (SUCCEEDED(result))
103     {
104         mNewClientRect = mClientRect;
105         mClientRectChanged = false;
106         return registerForSizeChangeEvents();
107     }
108 
109     return false;
110 }
111 
registerForSizeChangeEvents()112 bool CoreWindowNativeWindow::registerForSizeChangeEvents()
113 {
114     ComPtr<IWindowSizeChangedEventHandler> sizeChangedHandler;
115     HRESULT result = Microsoft::WRL::MakeAndInitialize<CoreWindowSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
116     if (SUCCEEDED(result))
117     {
118         result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
119     }
120 
121     if (SUCCEEDED(result))
122     {
123         return true;
124     }
125 
126     return false;
127 }
128 
unregisterForSizeChangeEvents()129 void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
130 {
131     if (mCoreWindow)
132     {
133         (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
134     }
135     mSizeChangedEventToken.value = 0;
136 }
137 
createSwapChain(ID3D11Device * device,IDXGIFactory2 * factory,DXGI_FORMAT format,unsigned int width,unsigned int height,bool containsAlpha,IDXGISwapChain1 ** swapChain)138 HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device,
139                                                 IDXGIFactory2 *factory,
140                                                 DXGI_FORMAT format,
141                                                 unsigned int width,
142                                                 unsigned int height,
143                                                 bool containsAlpha,
144                                                 IDXGISwapChain1 **swapChain)
145 {
146     if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 ||
147         height == 0)
148     {
149         return E_INVALIDARG;
150     }
151 
152     DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
153     swapChainDesc.Width = width;
154     swapChainDesc.Height = height;
155     swapChainDesc.Format = format;
156     swapChainDesc.Stereo = FALSE;
157     swapChainDesc.SampleDesc.Count = 1;
158     swapChainDesc.SampleDesc.Quality = 0;
159     swapChainDesc.BufferUsage =
160         DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
161     swapChainDesc.BufferCount = 2;
162     swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
163     swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
164     swapChainDesc.AlphaMode             = DXGI_ALPHA_MODE_UNSPECIFIED;
165 
166     *swapChain = nullptr;
167 
168     ComPtr<IDXGISwapChain1> newSwapChain;
169     HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
170     if (SUCCEEDED(result))
171     {
172         result = newSwapChain.CopyTo(swapChain);
173     }
174 
175     if (SUCCEEDED(result))
176     {
177         // If automatic swapchain resize behaviors have been disabled, then
178         // unregister for the resize change events.
179         if (mSupportsSwapChainResize == false)
180         {
181             unregisterForSizeChangeEvents();
182         }
183     }
184 
185     return result;
186 }
187 
scaleSwapChain(const Size & windowSize,const RECT & clientRect)188 inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize,
189                                                       const RECT &clientRect)
190 {
191     // We don't need to do any additional work to scale CoreWindow swapchains.
192     // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work.
193     return S_OK;
194 }
195 
GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> & coreWindow,Size * windowSize)196 HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> &coreWindow,
197                                   Size *windowSize)
198 {
199     ABI::Windows::Foundation::Rect bounds;
200     HRESULT result = coreWindow->get_Bounds(&bounds);
201     if (SUCCEEDED(result))
202     {
203         *windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
204     }
205 
206     return result;
207 }
208 }
209