| // |
| // 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<ABI::Windows::UI::Composition::ISpriteVisual *>(window); |
| mHostVisual = Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ISpriteVisual>{inspPtr}; |
| } |
| |
| CompositorNativeWindow11::~CompositorNativeWindow11() = default; |
| |
| bool CompositorNativeWindow11::initialize() |
| { |
| return true; |
| } |
| |
| bool CompositorNativeWindow11::getClientRect(LPRECT rect) const |
| { |
| ComPtr<ABI::Windows::UI::Composition::IVisual> 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<LONG>(offset.Y); |
| rect->left = static_cast<LONG>(offset.X); |
| rect->right = static_cast<LONG>(offset.X) + static_cast<LONG>(size.X); |
| rect->bottom = static_cast<LONG>(offset.Y) + static_cast<LONG>(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<ABI::Windows::UI::Composition::ICompositionObject> hostVisual; |
| hr = mHostVisual.As(&hostVisual); |
| if (FAILED(hr)) |
| { |
| return hr; |
| } |
| |
| Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ICompositor> compositor; |
| hr = hostVisual->get_Compositor(&compositor); |
| if (FAILED(hr)) |
| { |
| return hr; |
| } |
| |
| ComPtr<ABI::Windows::UI::Composition::ICompositorInterop> interop; |
| |
| hr = compositor.As(&interop); |
| if (FAILED(hr)) |
| { |
| return hr; |
| } |
| |
| ComPtr<IDXGIFactory2> factory2; |
| factory2.Attach(d3d11::DynamicCastComObject<IDXGIFactory2>(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; |
| swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; |
| Microsoft::WRL::ComPtr<IDXGISwapChain1> 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<ABI::Windows::UI::Composition::ISpriteVisual *>(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 <typename T> |
| bool AssignProcAddress(HMODULE comBaseModule, const char *name, T *&outProc) |
| { |
| outProc = reinterpret_cast<T *>(GetProcAddress(comBaseModule, name)); |
| return *outProc != nullptr; |
| } |
| |
| RoHelper::RoHelper() |
| : mFpWindowsCreateStringReference(nullptr), |
| mFpGetActivationFactory(nullptr), |
| mFpWindowsCompareStringOrdinal(nullptr), |
| mFpCreateDispatcherQueueController(nullptr), |
| mFpWindowsDeleteString(nullptr), |
| mFpRoInitialize(nullptr), |
| mFpRoUninitialize(nullptr), |
| mWinRtAvailable(false), |
| mComBaseModule(nullptr), |
| mCoreMessagingModule(nullptr) |
| { |
| if (!IsWindows10OrGreater()) |
| { |
| return; |
| } |
| |
| 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; |
| } |
| |
| if (SUCCEEDED(RoInitialize(RO_INIT_MULTITHREADED))) |
| { |
| mWinRtAvailable = true; |
| } |
| } |
| |
| RoHelper::~RoHelper() |
| { |
| if (mWinRtAvailable) |
| { |
| RoUninitialize(); |
| } |
| |
| if (mCoreMessagingModule != nullptr) |
| { |
| FreeLibrary(mCoreMessagingModule); |
| mCoreMessagingModule = nullptr; |
| } |
| |
| if (mComBaseModule != nullptr) |
| { |
| FreeLibrary(mComBaseModule); |
| mComBaseModule = nullptr; |
| } |
| } |
| |
| bool RoHelper::WinRtAvailable() const |
| { |
| return mWinRtAvailable; |
| } |
| |
| bool RoHelper::SupportedWindowsRelease() |
| { |
| if (!IsWindows10OrGreater() || !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<ABI::Windows::Foundation::Metadata::IApiInformationStatics> 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<const wchar_t *>(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 |