Edit

kc3-lang/angle/src/tests/egl_tests/EGLDirectCompositionTest.cpp

Branch :

  • Show log

    Commit

  • Author : Jonah Ryan-Davis
    Date : 2019-05-23 13:52:52
    Hash : f52f2637
    Message : Add EGL_ANGLE_workaround_control extension. This extension is used to query strings from an array based on index, which will be used to query all the information about workarounds in ANGLE. Bug: angleproject:1621 Change-Id: I27157f278f7f17c92c8b4fd7753e2a5ecd0528f6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1627723 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/egl_tests/EGLDirectCompositionTest.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 <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 "libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h"
    #include "util/OSWindow.h"
    #include "util/com_utils.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 testSetUp() override
        {
            if (!mRoHelper.SupportedWindowsRelease())
            {
                return;
            }
    
            // Create an OS Window
            mOSWindow = OSWindow::New();
    
            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(
                {static_cast<FLOAT>(WINDOWWIDTH), static_cast<FLOAT>(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 testTearDown() override
        {
            if (!mRoHelper.SupportedWindowsRelease())
            {
                return;
            }
            ASSERT_EGL_TRUE(eglTerminate(mEglDisplay));
    
            OSWindow::Delete(&mOSWindow);
        }
    
        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, WithNoFixture(ES2_D3D11()));