Commit 99d0463c by James Clarke Committed by Commit Bot

Windows: add support for SpriteVisuals as a native window type.

Enable SpriteVisuals to work along side HWNDs so that Angle rendered content can be hosted with Windows::UI::Composition APIs or XamlIslands in desktop Win32 applications. Includes a whitebox test, verified Win7 compatibility For more info see: https://docs.google.com/document/d/1ggv6H-aK1a3pXNMTtMF6h0Bv0rulIeBpBxBBCJYR6Zs/edit?usp=sharing Bug: angleproject:2947 Change-Id: Id005739553be2a6268cd4543f1b07aaf89760422 Reviewed-on: https://chromium-review.googlesource.com/c/1236844 Commit-Queue: James Clarke <james.clarke@microsoft.com> Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent a6e8a0c5
...@@ -109,6 +109,7 @@ Microsoft Corporation ...@@ -109,6 +109,7 @@ Microsoft Corporation
Minmin Gong Minmin Gong
Shawn Hargreaves Shawn Hargreaves
Rafael Cintron Rafael Cintron
James Clarke
Microsoft Open Technologies, Inc. Microsoft Open Technologies, Inc.
Cooper Partin Cooper Partin
......
...@@ -1342,6 +1342,7 @@ DisplayExtensions::DisplayExtensions() ...@@ -1342,6 +1342,7 @@ DisplayExtensions::DisplayExtensions()
getAllProcAddresses(false), getAllProcAddresses(false),
flexibleSurfaceCompatibility(false), flexibleSurfaceCompatibility(false),
directComposition(false), directComposition(false),
windowsUIComposition(false),
createContextNoError(false), createContextNoError(false),
stream(false), stream(false),
streamConsumerGLTexture(false), streamConsumerGLTexture(false),
...@@ -1380,6 +1381,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -1380,6 +1381,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_ANGLE_keyed_mutex", keyedMutex, &extensionStrings); InsertExtensionString("EGL_ANGLE_keyed_mutex", keyedMutex, &extensionStrings);
InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings); InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings);
InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings); InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings);
InsertExtensionString("EGL_ANGLE_windows_ui_composition", windowsUIComposition, &extensionStrings);
InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings); InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings);
InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings); InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings);
InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings); InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings);
......
...@@ -751,6 +751,9 @@ struct DisplayExtensions ...@@ -751,6 +751,9 @@ struct DisplayExtensions
// EGL_ANGLE_direct_composition // EGL_ANGLE_direct_composition
bool directComposition; bool directComposition;
// EGL_ANGLE_windows_ui_composition
bool windowsUIComposition;
// KHR_create_context_no_error // KHR_create_context_no_error
bool createContextNoError; bool createContextNoError;
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#ifdef ANGLE_ENABLE_WINDOWS_STORE #ifdef ANGLE_ENABLE_WINDOWS_STORE
#include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h" #include "libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h"
#else #else
#include "libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h"
#include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h" #include "libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h"
#endif #endif
...@@ -1186,6 +1187,12 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions ...@@ -1186,6 +1187,12 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions
// All D3D feature levels support robust resource init // All D3D feature levels support robust resource init
outExtensions->robustResourceInitialization = true; outExtensions->robustResourceInitialization = true;
// Compositor Native Window capabilies require WinVer >= 1803
if (CompositorNativeWindow11::IsSupportedWinRelease())
{
outExtensions->windowsUIComposition = true;
}
} }
angle::Result Renderer11::flush(Context11 *context11) angle::Result Renderer11::flush(Context11 *context11)
...@@ -1240,10 +1247,18 @@ angle::Result Renderer11::finish(Context11 *context11) ...@@ -1240,10 +1247,18 @@ angle::Result Renderer11::finish(Context11 *context11)
bool Renderer11::isValidNativeWindow(EGLNativeWindowType window) const bool Renderer11::isValidNativeWindow(EGLNativeWindowType window) const
{ {
static_assert(sizeof(ABI::Windows::UI::Composition::SpriteVisual *) == sizeof(HWND),
"Pointer size must match Window Handle size");
#ifdef ANGLE_ENABLE_WINDOWS_STORE #ifdef ANGLE_ENABLE_WINDOWS_STORE
return NativeWindow11WinRT::IsValidNativeWindow(window); return NativeWindow11WinRT::IsValidNativeWindow(window);
#else #else
return NativeWindow11Win32::IsValidNativeWindow(window); if (NativeWindow11Win32::IsValidNativeWindow(window))
{
return true;
}
return CompositorNativeWindow11::IsValidNativeWindow(window);
#endif #endif
} }
...@@ -1251,14 +1266,23 @@ NativeWindowD3D *Renderer11::createNativeWindow(EGLNativeWindowType window, ...@@ -1251,14 +1266,23 @@ NativeWindowD3D *Renderer11::createNativeWindow(EGLNativeWindowType window,
const egl::Config *config, const egl::Config *config,
const egl::AttributeMap &attribs) const const egl::AttributeMap &attribs) const
{ {
auto useWinUiComp = !NativeWindow11Win32::IsValidNativeWindow(window);
if (useWinUiComp)
{
return new CompositorNativeWindow11(window, config->alphaSize > 0);
}
else
{
#ifdef ANGLE_ENABLE_WINDOWS_STORE #ifdef ANGLE_ENABLE_WINDOWS_STORE
ANGLE_UNUSED_VARIABLE(attribs); UNUSED_VARIABLE(attribs);
return new NativeWindow11WinRT(window, config->alphaSize > 0); return new NativeWindow11WinRT(window, config->alphaSize > 0);
#else #else
return new NativeWindow11Win32( return new NativeWindow11Win32(
window, config->alphaSize > 0, window, config->alphaSize > 0,
attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE);
#endif #endif
}
} }
egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration, egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration,
......
//
// 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)
{
auto inspPtr = reinterpret_cast<ABI::Windows::UI::Composition::ISpriteVisual *>(window);
mHostVisual = Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ISpriteVisual>{inspPtr};
}
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 = {0};
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;
auto 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
//
// 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.h: Implementation of NativeWindow11 using Windows.UI.Composition APIs
// which work in both Win32 and WinRT contexts.
#ifndef LIBANGLE_RENDERER_D3D_D3D11_CONVERGED_COMPOSITORNATIVEWINDOW11_H_
#define LIBANGLE_RENDERER_D3D_D3D11_CONVERGED_COMPOSITORNATIVEWINDOW11_H_
#include "libANGLE/renderer/d3d/d3d11/NativeWindow11.h"
#include <DispatcherQueue.h>
#include <VersionHelpers.h>
#include <Windows.ui.composition.interop.h>
#include <windows.foundation.metadata.h>
#include <windows.ui.composition.h>
#include <wrl.h>
namespace rx
{
class RoHelper
{
public:
RoHelper();
~RoHelper();
bool WinRtAvailable() const;
bool SupportedWindowsRelease();
HRESULT GetStringReference(PCWSTR source, HSTRING *act, HSTRING_HEADER *header);
HRESULT GetActivationFactory(const HSTRING act, const IID &interfaceId, void **fac);
HRESULT WindowsCompareStringOrdinal(HSTRING one, HSTRING two, int *result);
HRESULT CreateDispatcherQueueController(
DispatcherQueueOptions options,
ABI::Windows::System::IDispatcherQueueController **dispatcherQueueController);
HRESULT WindowsDeleteString(HSTRING one);
HRESULT RoInitialize(RO_INIT_TYPE type);
void RoUninitialize();
private:
using WindowsCreateStringReference_ = HRESULT __stdcall(PCWSTR,
UINT32,
HSTRING_HEADER *,
HSTRING *);
using GetActivationFactory_ = HRESULT __stdcall(HSTRING, REFIID, void **);
using WindowsCompareStringOrginal_ = HRESULT __stdcall(HSTRING, HSTRING, int *);
using WindowsDeleteString_ = HRESULT __stdcall(HSTRING);
using CreateDispatcherQueueController_ =
HRESULT __stdcall(DispatcherQueueOptions,
ABI::Windows::System::IDispatcherQueueController **);
using RoInitialize_ = HRESULT __stdcall(RO_INIT_TYPE);
using RoUninitialize_ = void __stdcall();
WindowsCreateStringReference_ *mFpWindowsCreateStringReference;
GetActivationFactory_ *mFpGetActivationFactory;
WindowsCompareStringOrginal_ *mFpWindowsCompareStringOrdinal;
CreateDispatcherQueueController_ *mFpCreateDispatcherQueueController;
WindowsDeleteString_ *mFpWindowsDeleteString;
RoInitialize_ *mFpRoInitialize;
RoUninitialize_ *mFpRoUninitialize;
bool mWinRtAvailable;
HMODULE mComBaseModule;
HMODULE mCoreMessagingModule;
};
class CompositorNativeWindow11 : public NativeWindow11
{
public:
CompositorNativeWindow11(EGLNativeWindowType window, bool hasAlpha);
~CompositorNativeWindow11() override = default;
bool initialize() override;
bool getClientRect(LPRECT rect) const override;
bool isIconic() const override;
HRESULT createSwapChain(ID3D11Device *device,
IDXGIFactory *factory,
DXGI_FORMAT format,
UINT width,
UINT height,
UINT samples,
IDXGISwapChain **swapChain) override;
void commitChange() override;
static bool IsValidNativeWindow(EGLNativeWindowType window);
static bool IsSupportedWinRelease();
private:
static bool IsSpriteVisual(EGLNativeWindowType window);
bool mHasAlpha;
RoHelper mRoHelper;
// Namespace prefix required here for some reason despite using namespace
Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ISpriteVisual> mHostVisual;
Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ICompositionBrush> mCompositionBrush;
Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ICompositionSurface> mSurface;
Microsoft::WRL::ComPtr<ABI::Windows::UI::Composition::ICompositionSurfaceBrush> mSurfaceBrush;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_CONVERGED_COMPOSITORNATIVEWINDOW11_H_
\ No newline at end of file
...@@ -570,6 +570,8 @@ libangle_d3d11_sources = [ ...@@ -570,6 +570,8 @@ libangle_d3d11_sources = [
libangle_d3d11_win32_sources = [ libangle_d3d11_win32_sources = [
"src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp", "src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp",
"src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h", "src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.h",
"src/libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.cpp",
"src/libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h",
"src/third_party/systeminfo/SystemInfo.cpp", "src/third_party/systeminfo/SystemInfo.cpp",
"src/third_party/systeminfo/SystemInfo.h", "src/third_party/systeminfo/SystemInfo.h",
] ]
......
...@@ -13,6 +13,7 @@ angle_white_box_tests_sources = [ ...@@ -13,6 +13,7 @@ angle_white_box_tests_sources = [
"test_utils/gl_raii.h", "test_utils/gl_raii.h",
] ]
angle_white_box_tests_win_sources = [ angle_white_box_tests_win_sources = [
"egl_tests/EGLDirectCompositionTest.cpp",
"gl_tests/D3D11EmulatedIndexedBufferTest.cpp", "gl_tests/D3D11EmulatedIndexedBufferTest.cpp",
"gl_tests/D3D11FormatTablesTest.cpp", "gl_tests/D3D11FormatTablesTest.cpp",
"gl_tests/D3D11InputLayoutCacheTest.cpp", "gl_tests/D3D11InputLayoutCacheTest.cpp",
......
//
// 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.
//
// EGLDirectCompositionTest.cpp:
// Tests pertaining to DirectComposition and WindowsUIComposition.
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <d3d11.h>
#include "test_utils/ANGLETest.h"
#include <DispatcherQueue.h>
#include <VersionHelpers.h>
#include <Windows.Foundation.h>
#include <windows.ui.composition.Desktop.h>
#include <windows.ui.composition.h>
#include <windows.ui.composition.interop.h>
#include <wrl.h>
#include <memory>
#include "OSWindow.h"
#include "com_utils.h"
#include "libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h"
#include "test_utils/ANGLETest.h"
using namespace angle;
using namespace ABI::Windows::System;
using namespace ABI::Windows::UI::Composition;
using namespace ABI::Windows::UI::Composition::Desktop;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
const int WINDOWWIDTH = 200, WINDOWHEIGHT = 200;
class EGLDirectCompositionTest : public ANGLETest
{
protected:
EGLDirectCompositionTest() : mOSWindow(nullptr) {}
void SetUp() override
{
if (!mRoHelper.SupportedWindowsRelease())
{
return;
}
// Create an OS Window
mOSWindow = std::unique_ptr<OSWindow>(CreateOSWindow());
mOSWindow->initialize("EGLDirectCompositionTest", WINDOWWIDTH, WINDOWHEIGHT);
auto nativeWindow = mOSWindow->getNativeWindow();
mOSWindow->setVisible(true);
// Create DispatcherQueue for window to process compositor callbacks
CreateDispatcherQueue(mDispatcherController);
HSTRING act;
HSTRING_HEADER header;
auto hr = mRoHelper.GetStringReference(RuntimeClass_Windows_UI_Composition_Compositor, &act,
&header);
ASSERT_TRUE(SUCCEEDED(hr));
void *fac = nullptr;
hr = mRoHelper.GetActivationFactory(act, __uuidof(IActivationFactory), &fac);
ASSERT_TRUE(SUCCEEDED(hr));
ComPtr<IActivationFactory> compositorFactory;
compositorFactory.Attach((IActivationFactory *)fac);
hr = compositorFactory->ActivateInstance(&mCompositor);
ASSERT_TRUE(SUCCEEDED(hr));
// Create a DesktopWindowTarget against native window (HWND)
CreateDesktopWindowTarget(mCompositor, static_cast<HWND>(nativeWindow), mDesktopTarget);
ASSERT_TRUE(SUCCEEDED(mCompositor->CreateSpriteVisual(mAngleHost.GetAddressOf())));
ComPtr<IVisual> angleVis;
ASSERT_TRUE(SUCCEEDED(mAngleHost.As(&angleVis)));
ASSERT_TRUE(SUCCEEDED(angleVis->put_Size({WINDOWWIDTH, WINDOWHEIGHT})));
ASSERT_TRUE(SUCCEEDED(angleVis->put_Offset({0, 0, 0})));
ComPtr<ICompositionTarget> compTarget;
ASSERT_TRUE(SUCCEEDED(mDesktopTarget.As(&compTarget)));
ASSERT_TRUE(SUCCEEDED(compTarget->put_Root(angleVis.Get())));
Init();
}
void CreateDispatcherQueue(ComPtr<IDispatcherQueueController> &controller)
{
DispatcherQueueOptions options{sizeof(DispatcherQueueOptions), DQTYPE_THREAD_CURRENT,
DQTAT_COM_STA};
auto hr = mRoHelper.CreateDispatcherQueueController(options, controller.GetAddressOf());
ASSERT_TRUE(SUCCEEDED(hr));
}
void CreateDesktopWindowTarget(ComPtr<ICompositor> const &compositor,
const HWND window,
ComPtr<IDesktopWindowTarget> &target)
{
namespace abi = ABI::Windows::UI::Composition::Desktop;
ComPtr<ICompositorDesktopInterop> interop;
ASSERT_TRUE(SUCCEEDED(compositor.As(&interop)));
ASSERT_TRUE(SUCCEEDED(interop->CreateDesktopWindowTarget(
window, true, reinterpret_cast<abi::IDesktopWindowTarget **>(target.GetAddressOf()))));
}
void Init()
{
if (!mRoHelper.SupportedWindowsRelease())
{
return;
}
DPI_AWARENESS_CONTEXT
WINAPI
SetThreadDpiAwarenessContext(_In_ DPI_AWARENESS_CONTEXT dpiContext);
auto userModule = LoadLibraryA("user32.dll");
if (userModule == nullptr)
{
return;
}
auto temp = GetProcAddress(userModule, "SetThreadDpiAwarenessContext");
mFpSetThreadDpiAwarenessContext = reinterpret_cast<_SetThreadDpiAwarenessContext *>(temp);
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, EGL_NONE};
const EGLint defaultDisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE,
};
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplayEXT"));
ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY),
defaultDisplayAttributes);
ASSERT_TRUE(mEglDisplay != EGL_NO_DISPLAY);
ASSERT_EGL_TRUE(eglInitialize(mEglDisplay, nullptr, nullptr));
EGLint nConfigs = 0;
ASSERT_EGL_TRUE(eglGetConfigs(mEglDisplay, nullptr, 0, &nConfigs));
ASSERT_TRUE(nConfigs != 0);
ASSERT_EGL_TRUE(eglChooseConfig(mEglDisplay, configAttributes, &mEglConfig, 1, &nConfigs));
}
void CreateSurface(ComPtr<ABI::Windows::UI::Composition::ISpriteVisual> visual,
EGLSurface &surface)
{
auto displayExtensions = eglQueryString(mEglDisplay, EGL_EXTENSIONS);
// Check that the EGL_ANGLE_windows_ui_composition display extension is available
ASSERT_TRUE(strstr(displayExtensions, "EGL_ANGLE_windows_ui_composition") != nullptr);
const EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
// Use a spritevisual as the nativewindowtype
surface =
eglCreateWindowSurface(mEglDisplay, mEglConfig,
static_cast<EGLNativeWindowType>((void *)visual.Get()), nullptr);
ASSERT_TRUE(surface != EGL_NO_SURFACE);
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes);
ASSERT_TRUE(mEglContext != EGL_NO_CONTEXT);
ASSERT_TRUE(eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) != EGL_FALSE);
}
void TearDown() override
{
if (!mRoHelper.SupportedWindowsRelease())
{
return;
}
ASSERT_EGL_TRUE(eglTerminate(mEglDisplay));
}
std::unique_ptr<OSWindow> mOSWindow;
ComPtr<ICompositor> mCompositor;
ComPtr<IDispatcherQueueController> mDispatcherController;
ComPtr<ICompositionColorBrush> mColorBrush;
ComPtr<IDesktopWindowTarget> mDesktopTarget;
ComPtr<ISpriteVisual> mAngleHost;
EGLDisplay mEglDisplay;
EGLContext mEglContext;
EGLConfig mEglConfig;
rx::RoHelper mRoHelper;
using _SetThreadDpiAwarenessContext =
DPI_AWARENESS_CONTEXT WINAPI(DPI_AWARENESS_CONTEXT dpiContext);
_SetThreadDpiAwarenessContext *mFpSetThreadDpiAwarenessContext;
};
// This tests that a surface created using a SpriteVisual as container has the expected dimensions
// which should match the dimensions of the SpriteVisual passed in
TEST_P(EGLDirectCompositionTest, SurfaceSizeFromSpriteSize)
{
// Only attempt this test when on Windows 10 1803+
ANGLE_SKIP_TEST_IF(!mRoHelper.SupportedWindowsRelease());
EGLSurface s{nullptr};
CreateSurface(mAngleHost, s);
EGLint surfacewidth = 0, surfaceheight = 0;
eglQuerySurface(mEglDisplay, s, EGL_WIDTH, &surfacewidth);
eglQuerySurface(mEglDisplay, s, EGL_HEIGHT, &surfaceheight);
ComPtr<IVisual> angleVis;
ASSERT_TRUE(SUCCEEDED(mAngleHost.As(&angleVis)));
ABI::Windows::Foundation::Numerics::Vector2 visualsize{0, 0};
ASSERT_TRUE(SUCCEEDED(angleVis->get_Size(&visualsize)));
ASSERT_TRUE(surfacewidth == static_cast<int>(visualsize.X));
ASSERT_TRUE(surfaceheight == static_cast<int>(visualsize.Y));
ASSERT_EGL_TRUE(eglDestroySurface(mEglDisplay, s));
ASSERT_EGL_TRUE(eglDestroyContext(mEglDisplay, mEglContext));
}
// This tests that a WindowSurface can be created using a SpriteVisual as the containing window
// and that pixels can be successfully rendered into the resulting WindowSurface
TEST_P(EGLDirectCompositionTest, RenderSolidColor)
{
// Only attempt this test when on Windows 10 1803+
ANGLE_SKIP_TEST_IF(!mRoHelper.SupportedWindowsRelease());
EGLSurface s{nullptr};
CreateSurface(mAngleHost, s);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glViewport(0, 0, WINDOWWIDTH, WINDOWHEIGHT);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_EGL_TRUE(eglSwapBuffers(mEglDisplay, s));
// ensure user/DWM have a chance to paint the window and kick it to the top of the desktop
// zorder before we attempt to sample
angle::Sleep(200);
mOSWindow->messageLoop();
uint8_t *pixelBuffer = static_cast<uint8_t *>(malloc(WINDOWWIDTH * WINDOWHEIGHT * 4));
ZeroMemory(pixelBuffer, WINDOWWIDTH * WINDOWHEIGHT * 4);
// In order to accurately capture a bitmap, we need to temporarily shift into per-monitor DPI
// mode in order to get the window offset from desktop correct
auto previous = mFpSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
bool success = mOSWindow->takeScreenshot(pixelBuffer);
mFpSetThreadDpiAwarenessContext(previous);
ASSERT_EGL_TRUE(success);
ASSERT_EGL_TRUE(pixelBuffer[(50 * 50 * 4)] == 255);
ASSERT_EGL_TRUE(pixelBuffer[(50 * 50 * 4) + 1] == 0);
ASSERT_EGL_TRUE(pixelBuffer[(50 * 50 * 4) + 2] == 0);
ASSERT_EGL_TRUE(pixelBuffer[(50 * 50 * 4) + 3] == 255);
ASSERT_EGL_TRUE(eglDestroySurface(mEglDisplay, s));
ASSERT_EGL_TRUE(eglDestroyContext(mEglDisplay, mEglContext));
}
ANGLE_INSTANTIATE_TEST(EGLDirectCompositionTest, ES2_D3D11());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment