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 EGLRenderResolutionScaleProperty.");
68             return false;
69         }
70     }
71 
72     if (SUCCEEDED(result))
73     {
74         result = win.As(&mCoreWindow);
75     }
76 
77     if (SUCCEEDED(result))
78     {
79         // If a swapchain size is specfied, then the automatic resize
80         // behaviors implemented by the host should be disabled.  The swapchain
81         // will be still be scaled when being rendered to fit the bounds
82         // of the host.
83         // Scaling of the swapchain output occurs automatically because if
84         // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
85         if (mSwapChainSizeSpecified)
86         {
87             mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
88         }
89         else
90         {
91             Size coreWindowSize;
92             result = GetCoreWindowSizeInPixels(mCoreWindow, &coreWindowSize);
93 
94             if (SUCCEEDED(result))
95             {
96                 mClientRect = clientRect(coreWindowSize);
97             }
98         }
99     }
100 
101     if (SUCCEEDED(result))
102     {
103         mNewClientRect = mClientRect;
104         mClientRectChanged = false;
105         return registerForSizeChangeEvents();
106     }
107 
108     return false;
109 }
110 
registerForSizeChangeEvents()111 bool CoreWindowNativeWindow::registerForSizeChangeEvents()
112 {
113     ComPtr<IWindowSizeChangedEventHandler> sizeChangedHandler;
114     HRESULT result = Microsoft::WRL::MakeAndInitialize<CoreWindowSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
115     if (SUCCEEDED(result))
116     {
117         result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
118     }
119 
120     if (SUCCEEDED(result))
121     {
122         return true;
123     }
124 
125     return false;
126 }
127 
unregisterForSizeChangeEvents()128 void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
129 {
130     if (mCoreWindow)
131     {
132         (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
133     }
134     mSizeChangedEventToken.value = 0;
135 }
136 
createSwapChain(ID3D11Device * device,IDXGIFactory2 * factory,DXGI_FORMAT format,unsigned int width,unsigned int height,bool containsAlpha,IDXGISwapChain1 ** swapChain)137 HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device,
138                                                 IDXGIFactory2 *factory,
139                                                 DXGI_FORMAT format,
140                                                 unsigned int width,
141                                                 unsigned int height,
142                                                 bool containsAlpha,
143                                                 IDXGISwapChain1 **swapChain)
144 {
145     if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
146     {
147         return E_INVALIDARG;
148     }
149 
150     DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
151     swapChainDesc.Width = width;
152     swapChainDesc.Height = height;
153     swapChainDesc.Format = format;
154     swapChainDesc.Stereo = FALSE;
155     swapChainDesc.SampleDesc.Count = 1;
156     swapChainDesc.SampleDesc.Quality = 0;
157     swapChainDesc.BufferUsage =
158         DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
159     swapChainDesc.BufferCount = 2;
160     swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
161     swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
162     swapChainDesc.AlphaMode             = DXGI_ALPHA_MODE_UNSPECIFIED;
163 
164     *swapChain = nullptr;
165 
166     ComPtr<IDXGISwapChain1> newSwapChain;
167     HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
168     if (SUCCEEDED(result))
169     {
170         result = newSwapChain.CopyTo(swapChain);
171     }
172 
173     if (SUCCEEDED(result))
174     {
175         // If automatic swapchain resize behaviors have been disabled, then
176         // unregister for the resize change events.
177         if (mSupportsSwapChainResize == false)
178         {
179             unregisterForSizeChangeEvents();
180         }
181     }
182 
183     return result;
184 }
185 
scaleSwapChain(const Size & windowSize,const RECT & clientRect)186 inline HRESULT CoreWindowNativeWindow::scaleSwapChain(const Size &windowSize,
187                                                       const RECT &clientRect)
188 {
189     // We don't need to do any additional work to scale CoreWindow swapchains.
190     // Using DXGI_SCALING_STRETCH to create the swapchain above does all the necessary work.
191     return S_OK;
192 }
193 
GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> & coreWindow,Size * windowSize)194 HRESULT GetCoreWindowSizeInPixels(const ComPtr<ABI::Windows::UI::Core::ICoreWindow> &coreWindow,
195                                   Size *windowSize)
196 {
197     ABI::Windows::Foundation::Rect bounds;
198     HRESULT result = coreWindow->get_Bounds(&bounds);
199     if (SUCCEEDED(result))
200     {
201         *windowSize = { ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) };
202     }
203 
204     return result;
205 }
206 
GetLogicalDpi()207 static float GetLogicalDpi()
208 {
209     ComPtr<ABI::Windows::Graphics::Display::IDisplayPropertiesStatics> displayProperties;
210 
211     if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf())))
212     {
213         float dpi = 96.0f;
214         if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi)))
215         {
216             return dpi;
217         }
218     }
219 
220     // Return 96 dpi as a default if display properties cannot be obtained.
221     return 96.0f;
222 }
223 
ConvertDipsToPixels(float dips)224 float ConvertDipsToPixels(float dips)
225 {
226     static const float dipsPerInch = 96.0f;
227     return dips * GetLogicalDpi() / dipsPerInch;
228 }
229 }
230