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