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     swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
122     Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain1;
123     hr = factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1);
124     if (SUCCEEDED(hr))
125     {
126         swapChain1.CopyTo(swapChain);
127     }
128 
129     hr = interop->CreateCompositionSurfaceForSwapChain(swapChain1.Get(), &mSurface);
130     if (FAILED(hr))
131     {
132         return hr;
133     }
134 
135     hr = compositor->CreateSurfaceBrushWithSurface(mSurface.Get(), &mSurfaceBrush);
136     if (FAILED(hr))
137     {
138         return hr;
139     }
140 
141     hr = mSurfaceBrush.As(&mCompositionBrush);
142     if (FAILED(hr))
143     {
144         return hr;
145     }
146 
147     hr = mHostVisual->put_Brush(mCompositionBrush.Get());
148     if (FAILED(hr))
149     {
150         return hr;
151     }
152 
153     return hr;
154 }
155 
commitChange()156 void CompositorNativeWindow11::commitChange()
157 {
158     // Windows::UI::Composition uses an implicit commit model hence no action needed here
159 }
160 
161 // static
IsValidNativeWindow(EGLNativeWindowType window)162 bool CompositorNativeWindow11::IsValidNativeWindow(EGLNativeWindowType window)
163 {
164     return IsSupportedWinRelease() && IsSpriteVisual(window);
165 }
166 
167 // static
IsSupportedWinRelease()168 bool CompositorNativeWindow11::IsSupportedWinRelease()
169 {
170     RoHelper helper;
171     if (!helper.WinRtAvailable())
172     {
173         return false;
174     }
175 
176     return helper.SupportedWindowsRelease();
177 }
178 
IsSpriteVisual(EGLNativeWindowType window)179 bool CompositorNativeWindow11::IsSpriteVisual(EGLNativeWindowType window)
180 {
181     RoHelper helper;
182 
183     ABI::Windows::UI::Composition::ISpriteVisual *inspp =
184         reinterpret_cast<ABI::Windows::UI::Composition::ISpriteVisual *>(window);
185     HSTRING className, spriteClassName;
186     HSTRING_HEADER spriteClassNameHeader;
187 
188     auto hr = helper.GetStringReference(RuntimeClass_Windows_UI_Composition_SpriteVisual,
189                                         &spriteClassName, &spriteClassNameHeader);
190     if (FAILED(hr))
191     {
192         return false;
193     }
194 
195     hr = inspp->GetRuntimeClassName(&className);
196     if (FAILED(hr))
197     {
198         return false;
199     }
200 
201     INT32 result = -1;
202     hr           = helper.WindowsCompareStringOrdinal(className, spriteClassName, &result);
203 
204     helper.WindowsDeleteString(className);
205 
206     if (FAILED(hr))
207     {
208         return false;
209     }
210 
211     if (result == 0)
212     {
213         return true;
214     }
215 
216     return false;
217 }
218 
219 // RoHelperImpl
220 
221 template <typename T>
AssignProcAddress(HMODULE comBaseModule,const char * name,T * & outProc)222 bool AssignProcAddress(HMODULE comBaseModule, const char *name, T *&outProc)
223 {
224     outProc = reinterpret_cast<T *>(GetProcAddress(comBaseModule, name));
225     return *outProc != nullptr;
226 }
227 
RoHelper()228 RoHelper::RoHelper()
229     : mFpWindowsCreateStringReference(nullptr),
230       mFpGetActivationFactory(nullptr),
231       mFpWindowsCompareStringOrdinal(nullptr),
232       mFpCreateDispatcherQueueController(nullptr),
233       mFpWindowsDeleteString(nullptr),
234       mFpRoInitialize(nullptr),
235       mFpRoUninitialize(nullptr),
236       mWinRtAvailable(false),
237       mComBaseModule(nullptr),
238       mCoreMessagingModule(nullptr)
239 {
240     if (!IsWindows10OrGreater())
241     {
242         return;
243     }
244 
245     mComBaseModule = LoadLibraryA("ComBase.dll");
246 
247     if (mComBaseModule == nullptr)
248     {
249         return;
250     }
251 
252     if (!AssignProcAddress(mComBaseModule, "WindowsCreateStringReference",
253                            mFpWindowsCreateStringReference))
254     {
255         return;
256     }
257 
258     if (!AssignProcAddress(mComBaseModule, "RoGetActivationFactory", mFpGetActivationFactory))
259     {
260         return;
261     }
262 
263     if (!AssignProcAddress(mComBaseModule, "WindowsCompareStringOrdinal",
264                            mFpWindowsCompareStringOrdinal))
265     {
266         return;
267     }
268 
269     if (!AssignProcAddress(mComBaseModule, "WindowsDeleteString", mFpWindowsDeleteString))
270     {
271         return;
272     }
273 
274     if (!AssignProcAddress(mComBaseModule, "RoInitialize", mFpRoInitialize))
275     {
276         return;
277     }
278 
279     if (!AssignProcAddress(mComBaseModule, "RoUninitialize", mFpRoUninitialize))
280     {
281         return;
282     }
283 
284     mCoreMessagingModule = LoadLibraryA("coremessaging.dll");
285 
286     if (mCoreMessagingModule == nullptr)
287     {
288         return;
289     }
290 
291     if (!AssignProcAddress(mCoreMessagingModule, "CreateDispatcherQueueController",
292                            mFpCreateDispatcherQueueController))
293     {
294         return;
295     }
296 
297     if (SUCCEEDED(RoInitialize(RO_INIT_MULTITHREADED)))
298     {
299         mWinRtAvailable = true;
300     }
301 }
302 
~RoHelper()303 RoHelper::~RoHelper()
304 {
305     if (mWinRtAvailable)
306     {
307         RoUninitialize();
308     }
309 
310     if (mCoreMessagingModule != nullptr)
311     {
312         FreeLibrary(mCoreMessagingModule);
313         mCoreMessagingModule = nullptr;
314     }
315 
316     if (mComBaseModule != nullptr)
317     {
318         FreeLibrary(mComBaseModule);
319         mComBaseModule = nullptr;
320     }
321 }
322 
WinRtAvailable() const323 bool RoHelper::WinRtAvailable() const
324 {
325     return mWinRtAvailable;
326 }
327 
SupportedWindowsRelease()328 bool RoHelper::SupportedWindowsRelease()
329 {
330     if (!IsWindows10OrGreater() || !mWinRtAvailable)
331     {
332         return false;
333     }
334 
335     HSTRING className, contractName;
336     HSTRING_HEADER classNameHeader, contractNameHeader;
337     boolean isSupported = false;
338 
339     HRESULT hr = GetStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation,
340                                     &className, &classNameHeader);
341 
342     if (FAILED(hr))
343     {
344         return !!isSupported;
345     }
346 
347     Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Metadata::IApiInformationStatics> api;
348 
349     hr = GetActivationFactory(
350         className, __uuidof(ABI::Windows::Foundation::Metadata::IApiInformationStatics), &api);
351 
352     if (FAILED(hr))
353     {
354         return !!isSupported;
355     }
356 
357     hr = GetStringReference(L"Windows.Foundation.UniversalApiContract", &contractName,
358                             &contractNameHeader);
359     if (FAILED(hr))
360     {
361         return !!isSupported;
362     }
363 
364     api->IsApiContractPresentByMajor(contractName, 6, &isSupported);
365 
366     return !!isSupported;
367 }
368 
GetStringReference(PCWSTR source,HSTRING * act,HSTRING_HEADER * header)369 HRESULT RoHelper::GetStringReference(PCWSTR source, HSTRING *act, HSTRING_HEADER *header)
370 {
371     if (!mWinRtAvailable)
372     {
373         return E_FAIL;
374     }
375 
376     const wchar_t *str = static_cast<const wchar_t *>(source);
377 
378     unsigned int length;
379     HRESULT hr = SizeTToUInt32(::wcslen(str), &length);
380     if (FAILED(hr))
381     {
382         return hr;
383     }
384 
385     return mFpWindowsCreateStringReference(source, length, header, act);
386 }
387 
GetActivationFactory(const HSTRING act,const IID & interfaceId,void ** fac)388 HRESULT RoHelper::GetActivationFactory(const HSTRING act, const IID &interfaceId, void **fac)
389 {
390     if (!mWinRtAvailable)
391     {
392         return E_FAIL;
393     }
394     auto hr = mFpGetActivationFactory(act, interfaceId, fac);
395     return hr;
396 }
397 
WindowsCompareStringOrdinal(HSTRING one,HSTRING two,int * result)398 HRESULT RoHelper::WindowsCompareStringOrdinal(HSTRING one, HSTRING two, int *result)
399 {
400     if (!mWinRtAvailable)
401     {
402         return E_FAIL;
403     }
404     return mFpWindowsCompareStringOrdinal(one, two, result);
405 }
406 
CreateDispatcherQueueController(DispatcherQueueOptions options,ABI::Windows::System::IDispatcherQueueController ** dispatcherQueueController)407 HRESULT RoHelper::CreateDispatcherQueueController(
408     DispatcherQueueOptions options,
409     ABI::Windows::System::IDispatcherQueueController **dispatcherQueueController)
410 {
411     if (!mWinRtAvailable)
412     {
413         return E_FAIL;
414     }
415     return mFpCreateDispatcherQueueController(options, dispatcherQueueController);
416 }
417 
WindowsDeleteString(HSTRING one)418 HRESULT RoHelper::WindowsDeleteString(HSTRING one)
419 {
420     if (!mWinRtAvailable)
421     {
422         return E_FAIL;
423     }
424     return mFpWindowsDeleteString(one);
425 }
426 
RoInitialize(RO_INIT_TYPE type)427 HRESULT RoHelper::RoInitialize(RO_INIT_TYPE type)
428 {
429     return mFpRoInitialize(type);
430 }
431 
RoUninitialize()432 void RoHelper::RoUninitialize()
433 {
434     mFpRoUninitialize();
435 }
436 
437 }  // namespace rx
438