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