// // Copyright 2018 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // CompositorNativeWindow11.cpp: Implementation of NativeWindow11 using Windows.UI.Composition APIs // which work in both Win32 and WinRT contexts. #include "libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "common/debug.h" using namespace Microsoft::WRL; namespace rx { CompositorNativeWindow11::CompositorNativeWindow11(EGLNativeWindowType window, bool hasAlpha) : NativeWindow11(window), mHasAlpha(hasAlpha) { ABI::Windows::UI::Composition::ISpriteVisual *inspPtr = reinterpret_cast(window); mHostVisual = Microsoft::WRL::ComPtr{inspPtr}; } CompositorNativeWindow11::~CompositorNativeWindow11() = default; bool CompositorNativeWindow11::initialize() { return true; } bool CompositorNativeWindow11::getClientRect(LPRECT rect) const { ComPtr visual; mHostVisual.As(&visual); ABI::Windows::Foundation::Numerics::Vector2 size; HRESULT hr = visual->get_Size(&size); if (FAILED(hr)) { return false; } ABI::Windows::Foundation::Numerics::Vector3 offset; hr = visual->get_Offset(&offset); if (FAILED(hr)) { return false; } rect->top = static_cast(offset.Y); rect->left = static_cast(offset.X); rect->right = static_cast(offset.X) + static_cast(size.X); rect->bottom = static_cast(offset.Y) + static_cast(size.Y); return true; } bool CompositorNativeWindow11::isIconic() const { return false; } HRESULT CompositorNativeWindow11::createSwapChain(ID3D11Device *device, IDXGIFactory *factory, DXGI_FORMAT format, UINT width, UINT height, UINT samples, IDXGISwapChain **swapChain) { if (device == nullptr || factory == nullptr || swapChain == nullptr || width == 0 || height == 0) { return E_INVALIDARG; } HRESULT hr{E_FAIL}; ComPtr hostVisual; hr = mHostVisual.As(&hostVisual); if (FAILED(hr)) { return hr; } Microsoft::WRL::ComPtr compositor; hr = hostVisual->get_Compositor(&compositor); if (FAILED(hr)) { return hr; } ComPtr interop; hr = compositor.As(&interop); if (FAILED(hr)) { return hr; } ComPtr factory2; factory2.Attach(d3d11::DynamicCastComObject(factory)); DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.Width = width; swapChainDesc.Height = height; swapChainDesc.Format = format; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_SHADER_INPUT; swapChainDesc.BufferCount = 2; swapChainDesc.Scaling = DXGI_SCALING_STRETCH; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; swapChainDesc.AlphaMode = mHasAlpha ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; #ifndef ANGLE_ENABLE_WINDOWS_UWP swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; #endif Microsoft::WRL::ComPtr swapChain1; hr = factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1); if (SUCCEEDED(hr)) { swapChain1.CopyTo(swapChain); } hr = interop->CreateCompositionSurfaceForSwapChain(swapChain1.Get(), &mSurface); if (FAILED(hr)) { return hr; } hr = compositor->CreateSurfaceBrushWithSurface(mSurface.Get(), &mSurfaceBrush); if (FAILED(hr)) { return hr; } hr = mSurfaceBrush.As(&mCompositionBrush); if (FAILED(hr)) { return hr; } hr = mHostVisual->put_Brush(mCompositionBrush.Get()); if (FAILED(hr)) { return hr; } return hr; } void CompositorNativeWindow11::commitChange() { // Windows::UI::Composition uses an implicit commit model hence no action needed here } // static bool CompositorNativeWindow11::IsValidNativeWindow(EGLNativeWindowType window) { return IsSupportedWinRelease() && IsSpriteVisual(window); } // static bool CompositorNativeWindow11::IsSupportedWinRelease() { RoHelper helper; if (!helper.WinRtAvailable()) { return false; } return helper.SupportedWindowsRelease(); } bool CompositorNativeWindow11::IsSpriteVisual(EGLNativeWindowType window) { RoHelper helper; ABI::Windows::UI::Composition::ISpriteVisual *inspp = reinterpret_cast(window); HSTRING className, spriteClassName; HSTRING_HEADER spriteClassNameHeader; auto hr = helper.GetStringReference(RuntimeClass_Windows_UI_Composition_SpriteVisual, &spriteClassName, &spriteClassNameHeader); if (FAILED(hr)) { return false; } hr = inspp->GetRuntimeClassName(&className); if (FAILED(hr)) { return false; } INT32 result = -1; hr = helper.WindowsCompareStringOrdinal(className, spriteClassName, &result); helper.WindowsDeleteString(className); if (FAILED(hr)) { return false; } if (result == 0) { return true; } return false; } // RoHelperImpl template bool AssignProcAddress(HMODULE comBaseModule, const char *name, T *&outProc) { outProc = reinterpret_cast(GetProcAddress(comBaseModule, name)); return *outProc != nullptr; } RoHelper::RoHelper() : mFpWindowsCreateStringReference(nullptr), mFpGetActivationFactory(nullptr), mFpWindowsCompareStringOrdinal(nullptr), mFpCreateDispatcherQueueController(nullptr), mFpWindowsDeleteString(nullptr), mFpRoInitialize(nullptr), mFpRoUninitialize(nullptr), mWinRtAvailable(false), mWinRtInitialized(false), mComBaseModule(nullptr), mCoreMessagingModule(nullptr) { #ifdef ANGLE_ENABLE_WINDOWS_UWP mFpWindowsCreateStringReference = &::WindowsCreateStringReference; mFpRoInitialize = &::RoInitialize; mFpRoUninitialize = &::RoUninitialize; mFpWindowsDeleteString = &::WindowsDeleteString; mFpGetActivationFactory = &::RoGetActivationFactory; mFpWindowsCompareStringOrdinal = &::WindowsCompareStringOrdinal; mFpCreateDispatcherQueueController = &::CreateDispatcherQueueController; mWinRtAvailable = true; #else mComBaseModule = LoadLibraryA("ComBase.dll"); if (mComBaseModule == nullptr) { return; } if (!AssignProcAddress(mComBaseModule, "WindowsCreateStringReference", mFpWindowsCreateStringReference)) { return; } if (!AssignProcAddress(mComBaseModule, "RoGetActivationFactory", mFpGetActivationFactory)) { return; } if (!AssignProcAddress(mComBaseModule, "WindowsCompareStringOrdinal", mFpWindowsCompareStringOrdinal)) { return; } if (!AssignProcAddress(mComBaseModule, "WindowsDeleteString", mFpWindowsDeleteString)) { return; } if (!AssignProcAddress(mComBaseModule, "RoInitialize", mFpRoInitialize)) { return; } if (!AssignProcAddress(mComBaseModule, "RoUninitialize", mFpRoUninitialize)) { return; } mCoreMessagingModule = LoadLibraryA("coremessaging.dll"); if (mCoreMessagingModule == nullptr) { return; } if (!AssignProcAddress(mCoreMessagingModule, "CreateDispatcherQueueController", mFpCreateDispatcherQueueController)) { return; } auto result = RoInitialize(RO_INIT_MULTITHREADED); if (SUCCEEDED(result) || result == RPC_E_CHANGED_MODE) { mWinRtAvailable = true; if (SUCCEEDED(result)) { mWinRtInitialized = true; } } #endif } RoHelper::~RoHelper() { #ifndef ANGLE_ENABLE_WINDOWS_UWP if (mWinRtInitialized) { RoUninitialize(); } if (mCoreMessagingModule != nullptr) { FreeLibrary(mCoreMessagingModule); mCoreMessagingModule = nullptr; } if (mComBaseModule != nullptr) { FreeLibrary(mComBaseModule); mComBaseModule = nullptr; } #endif } bool RoHelper::WinRtAvailable() const { return mWinRtAvailable; } bool RoHelper::SupportedWindowsRelease() { if (!mWinRtAvailable) { return false; } HSTRING className, contractName; HSTRING_HEADER classNameHeader, contractNameHeader; boolean isSupported = false; HRESULT hr = GetStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation, &className, &classNameHeader); if (FAILED(hr)) { return !!isSupported; } Microsoft::WRL::ComPtr api; hr = GetActivationFactory( className, __uuidof(ABI::Windows::Foundation::Metadata::IApiInformationStatics), &api); if (FAILED(hr)) { return !!isSupported; } hr = GetStringReference(L"Windows.Foundation.UniversalApiContract", &contractName, &contractNameHeader); if (FAILED(hr)) { return !!isSupported; } api->IsApiContractPresentByMajor(contractName, 6, &isSupported); return !!isSupported; } HRESULT RoHelper::GetStringReference(PCWSTR source, HSTRING *act, HSTRING_HEADER *header) { if (!mWinRtAvailable) { return E_FAIL; } const wchar_t *str = static_cast(source); unsigned int length; HRESULT hr = SizeTToUInt32(::wcslen(str), &length); if (FAILED(hr)) { return hr; } return mFpWindowsCreateStringReference(source, length, header, act); } HRESULT RoHelper::GetActivationFactory(const HSTRING act, const IID &interfaceId, void **fac) { if (!mWinRtAvailable) { return E_FAIL; } auto hr = mFpGetActivationFactory(act, interfaceId, fac); return hr; } HRESULT RoHelper::WindowsCompareStringOrdinal(HSTRING one, HSTRING two, int *result) { if (!mWinRtAvailable) { return E_FAIL; } return mFpWindowsCompareStringOrdinal(one, two, result); } HRESULT RoHelper::CreateDispatcherQueueController( DispatcherQueueOptions options, ABI::Windows::System::IDispatcherQueueController **dispatcherQueueController) { if (!mWinRtAvailable) { return E_FAIL; } return mFpCreateDispatcherQueueController(options, dispatcherQueueController); } HRESULT RoHelper::WindowsDeleteString(HSTRING one) { if (!mWinRtAvailable) { return E_FAIL; } return mFpWindowsDeleteString(one); } HRESULT RoHelper::RoInitialize(RO_INIT_TYPE type) { return mFpRoInitialize(type); } void RoHelper::RoUninitialize() { mFpRoUninitialize(); } } // namespace rx