blob: 7203f87501c60ab450ab3aad4e465d53daf446c0 [file] [log] [blame]
//
// 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 <d3d11.h>
#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<PFN_D3D11_CREATE_DEVICE>(
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<const char *>(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<void *>(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<const char *>(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);
}