// // Copyright 2016 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. // // EGLSyncControlTest.cpp: // Tests pertaining to eglGetSyncValuesCHROMIUM. #include #include "test_utils/ANGLETest.h" #include "util/OSWindow.h" #include "util/com_utils.h" using namespace angle; class EGLSyncControlTest : public testing::Test { protected: EGLSyncControlTest() {} void SetUp() override { mD3D11Module = LoadLibrary(TEXT("d3d11.dll")); if (mD3D11Module == nullptr) { std::cout << "Unable to LoadLibrary D3D11" << std::endl; return; } mD3D11CreateDevice = reinterpret_cast( GetProcAddress(mD3D11Module, "D3D11CreateDevice")); if (mD3D11CreateDevice == nullptr) { std::cout << "Could not retrieve D3D11CreateDevice from d3d11.dll" << std::endl; return; } mD3D11Available = true; const char *extensionString = static_cast(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); if (strstr(extensionString, "EGL_ANGLE_device_creation")) { if (strstr(extensionString, "EGL_ANGLE_device_creation_d3d11")) { mDeviceCreationD3D11ExtAvailable = true; } } } void TearDown() override { SafeRelease(mDevice); SafeRelease(mDeviceContext); OSWindow::Delete(&mOSWindow); if (mSurface != EGL_NO_SURFACE) { eglDestroySurface(mDisplay, mSurface); mSurface = EGL_NO_SURFACE; } if (mContext != EGL_NO_CONTEXT) { eglDestroyContext(mDisplay, mContext); mContext = EGL_NO_CONTEXT; } if (mDisplay != EGL_NO_DISPLAY) { eglTerminate(mDisplay); mDisplay = EGL_NO_DISPLAY; } } void CreateD3D11Device() { ASSERT_TRUE(mD3D11Available); ASSERT_EQ(nullptr, mDevice); // The device shouldn't be created twice HRESULT hr = mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, nullptr, 0, D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, &mDeviceContext); ASSERT_TRUE(SUCCEEDED(hr)); } void InitializeDisplay() { EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE, EGL_NONE}; // Create an OS Window mOSWindow = OSWindow::New(); mOSWindow->initialize("EGLSyncControlTest", 64, 64); mOSWindow->setVisible(true); // Create an EGLDisplay using the EGLDevice mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast(mOSWindow->getNativeDisplay()), displayAttribs); ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); EGLint majorVersion, minorVersion; ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE); } void CreateWindowSurface() { eglBindAPI(EGL_OPENGL_ES_API); ASSERT_EGL_SUCCESS(); // Choose a config const EGLint configAttributes[] = {EGL_NONE}; EGLint configCount = 0; ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount)); const EGLint surfaceAttributes[] = {EGL_DIRECT_COMPOSITION_ANGLE, EGL_TRUE, EGL_NONE}; // Create window surface mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), surfaceAttributes); if (mSurface == nullptr) { std::cout << "Unable to create window surface with Direct Composition" << std::endl; return; } mDirectCompositionSurfaceAvailable = true; // Create EGL context EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes); ASSERT_EGL_SUCCESS(); // Make the surface current eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); ASSERT_EGL_SUCCESS(); } bool mD3D11Available = false; HMODULE mD3D11Module = nullptr; PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice = nullptr; ID3D11Device *mDevice = nullptr; ID3D11DeviceContext *mDeviceContext = nullptr; D3D_FEATURE_LEVEL mFeatureLevel; bool mDeviceCreationD3D11ExtAvailable = false; bool mDirectCompositionSurfaceAvailable = false; OSWindow *mOSWindow = nullptr; EGLDisplay mDisplay = EGL_NO_DISPLAY; EGLSurface mSurface = EGL_NO_SURFACE; EGLContext mContext = EGL_NO_CONTEXT; EGLConfig mConfig = 0; }; // Basic test for eglGetSyncValuesCHROMIUM extension. Verifies that eglGetSyncValuesCHROMIUM // can be called on DX11 with direct composition and that it returns reasonable enough values. TEST_F(EGLSyncControlTest, DISABLED_SyncValuesTest) { static const DWORD kPollInterval = 10; static const int kNumPollIterations = 100; if (!mD3D11Available) { std::cout << "D3D11 not available, skipping test" << std::endl; return; } CreateD3D11Device(); InitializeDisplay(); CreateWindowSurface(); if (!mDirectCompositionSurfaceAvailable) { std::cout << "Direct Composition surface not available, skipping test" << std::endl; return; } const char *extensionString = static_cast(eglQueryString(mDisplay, EGL_EXTENSIONS)); ASSERT_TRUE(strstr(extensionString, "EGL_CHROMIUM_sync_control")); EGLuint64KHR ust = 0, msc = 0, sbc = 0; // It appears there is a race condition so the very first call to eglGetSyncValuesCHROMIUM // can fail within D3D with DXGI_ERROR_FRAME_STATISTICS_DISJOINT. // Should that be handled inside eglGetSyncValuesCHROMIUM? eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc); ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc)); // Initial msc and sbc value should be true. Initial ust value is unspecified. ASSERT_EQ(0ull, msc); ASSERT_EQ(0ull, sbc); // Perform some very basic rendering. glClearColor(1.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ASSERT_GL_NO_ERROR(); ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface)); // Poll until sbc value increases. Normally it should change within 16-17 ms. for (int i = 0; i < kNumPollIterations; i++) { ::Sleep(kPollInterval); ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc)); if (sbc > 0) break; } // sbc should change to 1. msc and ust to some non-zero values. ASSERT_EQ(1ull, sbc); ASSERT_GT(ust, 0ull); ASSERT_GT(msc, 0ull); // Perform more rendering. glClearColor(0.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ASSERT_GL_NO_ERROR(); ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface)); // Poll until sbc value increases. Normally it should change within 16-17 ms. EGLuint64KHR ust2 = 0, msc2 = 0, sbc2 = 0; for (int i = 0; i < kNumPollIterations; i++) { ::Sleep(kPollInterval); ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust2, &msc2, &sbc2)); if (sbc2 > sbc) break; } // sbc2 should be 2. msc2 and ust2 should be greater than previous msc and ust values. ASSERT_EQ(2ull, sbc2); ASSERT_GT(ust2, ust); ASSERT_GT(msc2, msc); }