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