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 mWinRtInitialized(false),
240 mComBaseModule(nullptr),
241 mCoreMessagingModule(nullptr)
242 {
243
244 #ifdef ANGLE_ENABLE_WINDOWS_UWP
245 mFpWindowsCreateStringReference = &::WindowsCreateStringReference;
246 mFpRoInitialize = &::RoInitialize;
247 mFpRoUninitialize = &::RoUninitialize;
248 mFpWindowsDeleteString = &::WindowsDeleteString;
249 mFpGetActivationFactory = &::RoGetActivationFactory;
250 mFpWindowsCompareStringOrdinal = &::WindowsCompareStringOrdinal;
251 mFpCreateDispatcherQueueController = &::CreateDispatcherQueueController;
252 mWinRtAvailable = true;
253 #else
254
255 mComBaseModule = LoadLibraryA("ComBase.dll");
256
257 if (mComBaseModule == nullptr)
258 {
259 return;
260 }
261
262 if (!AssignProcAddress(mComBaseModule, "WindowsCreateStringReference",
263 mFpWindowsCreateStringReference))
264 {
265 return;
266 }
267
268 if (!AssignProcAddress(mComBaseModule, "RoGetActivationFactory", mFpGetActivationFactory))
269 {
270 return;
271 }
272
273 if (!AssignProcAddress(mComBaseModule, "WindowsCompareStringOrdinal",
274 mFpWindowsCompareStringOrdinal))
275 {
276 return;
277 }
278
279 if (!AssignProcAddress(mComBaseModule, "WindowsDeleteString", mFpWindowsDeleteString))
280 {
281 return;
282 }
283
284 if (!AssignProcAddress(mComBaseModule, "RoInitialize", mFpRoInitialize))
285 {
286 return;
287 }
288
289 if (!AssignProcAddress(mComBaseModule, "RoUninitialize", mFpRoUninitialize))
290 {
291 return;
292 }
293
294 mCoreMessagingModule = LoadLibraryA("coremessaging.dll");
295
296 if (mCoreMessagingModule == nullptr)
297 {
298 return;
299 }
300
301 if (!AssignProcAddress(mCoreMessagingModule, "CreateDispatcherQueueController",
302 mFpCreateDispatcherQueueController))
303 {
304 return;
305 }
306
307 auto result = RoInitialize(RO_INIT_MULTITHREADED);
308
309 if (SUCCEEDED(result) || result == RPC_E_CHANGED_MODE)
310 {
311 mWinRtAvailable = true;
312
313 if (SUCCEEDED(result))
314 {
315 mWinRtInitialized = true;
316 }
317 }
318 #endif
319 }
320
~RoHelper()321 RoHelper::~RoHelper()
322 {
323 #ifndef ANGLE_ENABLE_WINDOWS_UWP
324 if (mWinRtInitialized)
325 {
326 RoUninitialize();
327 }
328
329 if (mCoreMessagingModule != nullptr)
330 {
331 FreeLibrary(mCoreMessagingModule);
332 mCoreMessagingModule = nullptr;
333 }
334
335 if (mComBaseModule != nullptr)
336 {
337 FreeLibrary(mComBaseModule);
338 mComBaseModule = nullptr;
339 }
340 #endif
341 }
342
WinRtAvailable() const343 bool RoHelper::WinRtAvailable() const
344 {
345 return mWinRtAvailable;
346 }
347
SupportedWindowsRelease()348 bool RoHelper::SupportedWindowsRelease()
349 {
350 if (!mWinRtAvailable)
351 {
352 return false;
353 }
354
355 HSTRING className, contractName;
356 HSTRING_HEADER classNameHeader, contractNameHeader;
357 boolean isSupported = false;
358
359 HRESULT hr = GetStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation,
360 &className, &classNameHeader);
361
362 if (FAILED(hr))
363 {
364 return !!isSupported;
365 }
366
367 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Metadata::IApiInformationStatics> api;
368
369 hr = GetActivationFactory(
370 className, __uuidof(ABI::Windows::Foundation::Metadata::IApiInformationStatics), &api);
371
372 if (FAILED(hr))
373 {
374 return !!isSupported;
375 }
376
377 hr = GetStringReference(L"Windows.Foundation.UniversalApiContract", &contractName,
378 &contractNameHeader);
379 if (FAILED(hr))
380 {
381 return !!isSupported;
382 }
383
384 api->IsApiContractPresentByMajor(contractName, 6, &isSupported);
385
386 return !!isSupported;
387 }
388
GetStringReference(PCWSTR source,HSTRING * act,HSTRING_HEADER * header)389 HRESULT RoHelper::GetStringReference(PCWSTR source, HSTRING *act, HSTRING_HEADER *header)
390 {
391 if (!mWinRtAvailable)
392 {
393 return E_FAIL;
394 }
395
396 const wchar_t *str = static_cast<const wchar_t *>(source);
397
398 unsigned int length;
399 HRESULT hr = SizeTToUInt32(::wcslen(str), &length);
400 if (FAILED(hr))
401 {
402 return hr;
403 }
404
405 return mFpWindowsCreateStringReference(source, length, header, act);
406 }
407
GetActivationFactory(const HSTRING act,const IID & interfaceId,void ** fac)408 HRESULT RoHelper::GetActivationFactory(const HSTRING act, const IID &interfaceId, void **fac)
409 {
410 if (!mWinRtAvailable)
411 {
412 return E_FAIL;
413 }
414 auto hr = mFpGetActivationFactory(act, interfaceId, fac);
415 return hr;
416 }
417
WindowsCompareStringOrdinal(HSTRING one,HSTRING two,int * result)418 HRESULT RoHelper::WindowsCompareStringOrdinal(HSTRING one, HSTRING two, int *result)
419 {
420 if (!mWinRtAvailable)
421 {
422 return E_FAIL;
423 }
424 return mFpWindowsCompareStringOrdinal(one, two, result);
425 }
426
CreateDispatcherQueueController(DispatcherQueueOptions options,ABI::Windows::System::IDispatcherQueueController ** dispatcherQueueController)427 HRESULT RoHelper::CreateDispatcherQueueController(
428 DispatcherQueueOptions options,
429 ABI::Windows::System::IDispatcherQueueController **dispatcherQueueController)
430 {
431 if (!mWinRtAvailable)
432 {
433 return E_FAIL;
434 }
435 return mFpCreateDispatcherQueueController(options, dispatcherQueueController);
436 }
437
WindowsDeleteString(HSTRING one)438 HRESULT RoHelper::WindowsDeleteString(HSTRING one)
439 {
440 if (!mWinRtAvailable)
441 {
442 return E_FAIL;
443 }
444 return mFpWindowsDeleteString(one);
445 }
446
RoInitialize(RO_INIT_TYPE type)447 HRESULT RoHelper::RoInitialize(RO_INIT_TYPE type)
448 {
449 return mFpRoInitialize(type);
450 }
451
RoUninitialize()452 void RoHelper::RoUninitialize()
453 {
454 mFpRoUninitialize();
455 }
456
457 } // namespace rx
458