blob: 8903ca9973e0256997c654cbaa1106db3e297d4d [file] [log] [blame]
//
// 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