1 //
2 // Copyright 2018 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 // CompositorNativeWindow11.cpp: Implementation of NativeWindow11 using Windows.UI.Composition APIs
8 // which work in both Win32 and WinRT contexts.
9
10 #include "libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h"
11 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
12
13 #include "common/debug.h"
14
15 using namespace Microsoft::WRL;
16
17 namespace rx
18 {
19
CompositorNativeWindow11(EGLNativeWindowType window,bool hasAlpha)20 CompositorNativeWindow11::CompositorNativeWindow11(EGLNativeWindowType window, bool hasAlpha)
21 : NativeWindow11(window), mHasAlpha(hasAlpha)
22 {
23 ABI::Windows::UI::Composition::ISpriteVisual *inspPtr =
24 reinterpret_cast<ABI::Windows::UI::Composition::ISpriteVisual *>(window);
25 mHostVisual = Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ISpriteVisual>{inspPtr};
26 }
27
28 CompositorNativeWindow11::~CompositorNativeWindow11() = default;
29
initialize()30 bool CompositorNativeWindow11::initialize()
31 {
32 return true;
33 }
34
getClientRect(LPRECT rect) const35 bool CompositorNativeWindow11::getClientRect(LPRECT rect) const
36 {
37 ComPtr<ABI::Windows::UI::Composition::IVisual> visual;
38 mHostVisual.As(&visual);
39
40 ABI::Windows::Foundation::Numerics::Vector2 size;
41 HRESULT hr = visual->get_Size(&size);
42 if (FAILED(hr))
43 {
44 return false;
45 }
46
47 ABI::Windows::Foundation::Numerics::Vector3 offset;
48 hr = visual->get_Offset(&offset);
49 if (FAILED(hr))
50 {
51 return false;
52 }
53
54 rect->top = static_cast<LONG>(offset.Y);
55 rect->left = static_cast<LONG>(offset.X);
56 rect->right = static_cast<LONG>(offset.X) + static_cast<LONG>(size.X);
57 rect->bottom = static_cast<LONG>(offset.Y) + static_cast<LONG>(size.Y);
58
59 return true;
60 }
61
isIconic() const62 bool CompositorNativeWindow11::isIconic() const
63 {
64 return false;
65 }
66
createSwapChain(ID3D11Device * device,IDXGIFactory * factory,DXGI_FORMAT format,UINT width,UINT height,UINT samples,IDXGISwapChain ** swapChain)67 HRESULT CompositorNativeWindow11::createSwapChain(ID3D11Device *device,
68 IDXGIFactory *factory,
69 DXGI_FORMAT format,
70 UINT width,
71 UINT height,
72 UINT samples,
73 IDXGISwapChain **swapChain)
74 {
75 if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 ||
76 height == 0)
77 {
78 return E_INVALIDARG;
79 }
80
81 HRESULT hr{E_FAIL};
82
83 ComPtr<ABI::Windows::UI::Composition::ICompositionObject> hostVisual;
84 hr = mHostVisual.As(&hostVisual);
85 if (FAILED(hr))
86 {
87 return hr;
88 }
89
90 Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ICompositor> compositor;
91 hr = hostVisual->get_Compositor(&compositor);
92 if (FAILED(hr))
93 {
94 return hr;
95 }
96
97 ComPtr<ABI::Windows::UI::Composition::ICompositorInterop> interop;
98
99 hr = compositor.As(&interop);
100 if (FAILED(hr))
101 {
102 return hr;
103 }
104
105 ComPtr<IDXGIFactory2> factory2;
106 factory2.Attach(d3d11::DynamicCastComObject<IDXGIFactory2>(factory));
107
108 DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
109 swapChainDesc.Width = width;
110 swapChainDesc.Height = height;
111 swapChainDesc.Format = format;
112 swapChainDesc.Stereo = FALSE;
113 swapChainDesc.SampleDesc.Count = 1;
114 swapChainDesc.SampleDesc.Quality = 0;
115 swapChainDesc.BufferUsage =
116 DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_SHADER_INPUT;
117 swapChainDesc.BufferCount = 2;
118 swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
119 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
120 swapChainDesc.AlphaMode = mHasAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
121 #ifndef ANGLE_ENABLE_WINDOWS_UWP
122 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
123 #endif
124 Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain1;
125 hr = factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1);
126 if (SUCCEEDED(hr))
127 {
128 swapChain1.CopyTo(swapChain);
129 }
130
131 hr = interop->CreateCompositionSurfaceForSwapChain(swapChain1.Get(), &mSurface);
132 if (FAILED(hr))
133 {
134 return hr;
135 }
136
137 hr = compositor->CreateSurfaceBrushWithSurface(mSurface.Get(), &mSurfaceBrush);
138 if (FAILED(hr))
139 {
140 return hr;
141 }
142
143 hr = mSurfaceBrush.As(&mCompositionBrush);
144 if (FAILED(hr))
145 {
146 return hr;
147 }
148
149 hr = mHostVisual->put_Brush(mCompositionBrush.Get());
150 if (FAILED(hr))
151 {
152 return hr;
153 }
154
155 return hr;
156 }
157
commitChange()158 void CompositorNativeWindow11::commitChange()
159 {
160 // Windows::UI::Composition uses an implicit commit model hence no action needed here
161 }
162
163 // static
IsValidNativeWindow(EGLNativeWindowType window)164 bool CompositorNativeWindow11::IsValidNativeWindow(EGLNativeWindowType window)
165 {
166 return IsSupportedWinRelease() && IsSpriteVisual(window);
167 }
168
169 // static
IsSupportedWinRelease()170 bool CompositorNativeWindow11::IsSupportedWinRelease()
171 {
172 RoHelper helper;
173 if (!helper.WinRtAvailable())
174 {
175 return false;
176 }
177
178 return helper.SupportedWindowsRelease();
179 }
180
IsSpriteVisual(EGLNativeWindowType window)181 bool CompositorNativeWindow11::IsSpriteVisual(EGLNativeWindowType window)
182 {
183 RoHelper helper;
184
185 ABI::Windows::UI::Composition::ISpriteVisual *inspp =
186 reinterpret_cast<ABI::Windows::UI::Composition::ISpriteVisual *>(window);
187 HSTRING className, spriteClassName;
188 HSTRING_HEADER spriteClassNameHeader;
189
190 auto hr = helper.GetStringReference(RuntimeClass_Windows_UI_Composition_SpriteVisual,
191 &spriteClassName, &spriteClassNameHeader);
192 if (FAILED(hr))
193 {
194 return false;
195 }
196
197 hr = inspp->GetRuntimeClassName(&className);
198 if (FAILED(hr))
199 {
200 return false;
201 }
202
203 INT32 result = -1;
204 hr = helper.WindowsCompareStringOrdinal(className, spriteClassName, &result);
205
206 helper.WindowsDeleteString(className);
207
208 if (FAILED(hr))
209 {
210 return false;
211 }
212
213 if (result == 0)
214 {
215 return true;
216 }
217
218 return false;
219 }
220
221 // RoHelperImpl
222
223 template <typename T>
AssignProcAddress(HMODULE comBaseModule,const char * name,T * & outProc)224 bool AssignProcAddress(HMODULE comBaseModule, const char *name, T *&outProc)
225 {
226 outProc = reinterpret_cast<T *>(GetProcAddress(comBaseModule, name));
227 return *outProc != nullptr;
228 }
229
RoHelper()230 RoHelper::RoHelper()
231 : mFpWindowsCreateStringReference(nullptr),
232 mFpGetActivationFactory(nullptr),
233 mFpWindowsCompareStringOrdinal(nullptr),
234 mFpCreateDispatcherQueueController(nullptr),
235 mFpWindowsDeleteString(nullptr),
236 mFpRoInitialize(nullptr),
237 mFpRoUninitialize(nullptr),
238 mWinRtAvailable(false),
239 mComBaseModule(nullptr),
240 mCoreMessagingModule(nullptr)
241 {
242
243 #ifdef ANGLE_ENABLE_WINDOWS_UWP
244 mFpWindowsCreateStringReference = &::WindowsCreateStringReference;
245 mFpRoInitialize = &::RoInitialize;
246 mFpRoUninitialize = &::RoUninitialize;
247 mFpWindowsDeleteString = &::WindowsDeleteString;
248 mFpGetActivationFactory = &::RoGetActivationFactory;
249 mFpWindowsCompareStringOrdinal = &::WindowsCompareStringOrdinal;
250 mFpCreateDispatcherQueueController = &::CreateDispatcherQueueController;
251 mWinRtAvailable = true;
252 #else
253
254 mComBaseModule = LoadLibraryA("ComBase.dll");
255
256 if (mComBaseModule == nullptr)
257 {
258 return;
259 }
260
261 if (!AssignProcAddress(mComBaseModule, "WindowsCreateStringReference",
262 mFpWindowsCreateStringReference))
263 {
264 return;
265 }
266
267 if (!AssignProcAddress(mComBaseModule, "RoGetActivationFactory", mFpGetActivationFactory))
268 {
269 return;
270 }
271
272 if (!AssignProcAddress(mComBaseModule, "WindowsCompareStringOrdinal",
273 mFpWindowsCompareStringOrdinal))
274 {
275 return;
276 }
277
278 if (!AssignProcAddress(mComBaseModule, "WindowsDeleteString", mFpWindowsDeleteString))
279 {
280 return;
281 }
282
283 if (!AssignProcAddress(mComBaseModule, "RoInitialize", mFpRoInitialize))
284 {
285 return;
286 }
287
288 if (!AssignProcAddress(mComBaseModule, "RoUninitialize", mFpRoUninitialize))
289 {
290 return;
291 }
292
293 mCoreMessagingModule = LoadLibraryA("coremessaging.dll");
294
295 if (mCoreMessagingModule == nullptr)
296 {
297 return;
298 }
299
300 if (!AssignProcAddress(mCoreMessagingModule, "CreateDispatcherQueueController",
301 mFpCreateDispatcherQueueController))
302 {
303 return;
304 }
305
306 auto result = RoInitialize(RO_INIT_MULTITHREADED);
307
308 if (SUCCEEDED(result) || result == S_FALSE || result == RPC_E_CHANGED_MODE)
309 {
310 mWinRtAvailable = true;
311 }
312 #endif
313 }
314
~RoHelper()315 RoHelper::~RoHelper()
316 {
317 #ifndef ANGLE_ENABLE_WINDOWS_UWP
318 if (mWinRtAvailable)
319 {
320 RoUninitialize();
321 }
322
323 if (mCoreMessagingModule != nullptr)
324 {
325 FreeLibrary(mCoreMessagingModule);
326 mCoreMessagingModule = nullptr;
327 }
328
329 if (mComBaseModule != nullptr)
330 {
331 FreeLibrary(mComBaseModule);
332 mComBaseModule = nullptr;
333 }
334 #endif
335 }
336
WinRtAvailable() const337 bool RoHelper::WinRtAvailable() const
338 {
339 return mWinRtAvailable;
340 }
341
SupportedWindowsRelease()342 bool RoHelper::SupportedWindowsRelease()
343 {
344 if (!mWinRtAvailable)
345 {
346 return false;
347 }
348
349 HSTRING className, contractName;
350 HSTRING_HEADER classNameHeader, contractNameHeader;
351 boolean isSupported = false;
352
353 HRESULT hr = GetStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation,
354 &className, &classNameHeader);
355
356 if (FAILED(hr))
357 {
358 return !!isSupported;
359 }
360
361 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Metadata::IApiInformationStatics> api;
362
363 hr = GetActivationFactory(
364 className, __uuidof(ABI::Windows::Foundation::Metadata::IApiInformationStatics), &api);
365
366 if (FAILED(hr))
367 {
368 return !!isSupported;
369 }
370
371 hr = GetStringReference(L"Windows.Foundation.UniversalApiContract", &contractName,
372 &contractNameHeader);
373 if (FAILED(hr))
374 {
375 return !!isSupported;
376 }
377
378 api->IsApiContractPresentByMajor(contractName, 6, &isSupported);
379
380 return !!isSupported;
381 }
382
GetStringReference(PCWSTR source,HSTRING * act,HSTRING_HEADER * header)383 HRESULT RoHelper::GetStringReference(PCWSTR source, HSTRING *act, HSTRING_HEADER *header)
384 {
385 if (!mWinRtAvailable)
386 {
387 return E_FAIL;
388 }
389
390 const wchar_t *str = static_cast<const wchar_t *>(source);
391
392 unsigned int length;
393 HRESULT hr = SizeTToUInt32(::wcslen(str), &length);
394 if (FAILED(hr))
395 {
396 return hr;
397 }
398
399 return mFpWindowsCreateStringReference(source, length, header, act);
400 }
401
GetActivationFactory(const HSTRING act,const IID & interfaceId,void ** fac)402 HRESULT RoHelper::GetActivationFactory(const HSTRING act, const IID &interfaceId, void **fac)
403 {
404 if (!mWinRtAvailable)
405 {
406 return E_FAIL;
407 }
408 auto hr = mFpGetActivationFactory(act, interfaceId, fac);
409 return hr;
410 }
411
WindowsCompareStringOrdinal(HSTRING one,HSTRING two,int * result)412 HRESULT RoHelper::WindowsCompareStringOrdinal(HSTRING one, HSTRING two, int *result)
413 {
414 if (!mWinRtAvailable)
415 {
416 return E_FAIL;
417 }
418 return mFpWindowsCompareStringOrdinal(one, two, result);
419 }
420
CreateDispatcherQueueController(DispatcherQueueOptions options,ABI::Windows::System::IDispatcherQueueController ** dispatcherQueueController)421 HRESULT RoHelper::CreateDispatcherQueueController(
422 DispatcherQueueOptions options,
423 ABI::Windows::System::IDispatcherQueueController **dispatcherQueueController)
424 {
425 if (!mWinRtAvailable)
426 {
427 return E_FAIL;
428 }
429 return mFpCreateDispatcherQueueController(options, dispatcherQueueController);
430 }
431
WindowsDeleteString(HSTRING one)432 HRESULT RoHelper::WindowsDeleteString(HSTRING one)
433 {
434 if (!mWinRtAvailable)
435 {
436 return E_FAIL;
437 }
438 return mFpWindowsDeleteString(one);
439 }
440
RoInitialize(RO_INIT_TYPE type)441 HRESULT RoHelper::RoInitialize(RO_INIT_TYPE type)
442 {
443 return mFpRoInitialize(type);
444 }
445
RoUninitialize()446 void RoHelper::RoUninitialize()
447 {
448 mFpRoUninitialize();
449 }
450
451 } // namespace rx
452