xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLSyncControlTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // EGLSyncControlTest.cpp:
8 //   Tests pertaining to eglGetSyncValuesCHROMIUM.
9 
10 #include <d3d11.h>
11 
12 #include "test_utils/ANGLETest.h"
13 #include "util/OSWindow.h"
14 #include "util/com_utils.h"
15 
16 using namespace angle;
17 
18 class EGLSyncControlTest : public testing::Test
19 {
20   protected:
EGLSyncControlTest()21     EGLSyncControlTest() {}
22 
SetUp()23     void SetUp() override
24     {
25         mD3D11Module = LoadLibrary(TEXT("d3d11.dll"));
26         if (mD3D11Module == nullptr)
27         {
28             std::cout << "Unable to LoadLibrary D3D11" << std::endl;
29             return;
30         }
31 
32         mD3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
33             GetProcAddress(mD3D11Module, "D3D11CreateDevice"));
34         if (mD3D11CreateDevice == nullptr)
35         {
36             std::cout << "Could not retrieve D3D11CreateDevice from d3d11.dll" << std::endl;
37             return;
38         }
39 
40         mD3D11Available = true;
41 
42         const char *extensionString =
43             static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
44         if (strstr(extensionString, "EGL_ANGLE_device_creation"))
45         {
46             if (strstr(extensionString, "EGL_ANGLE_device_creation_d3d11"))
47             {
48                 mDeviceCreationD3D11ExtAvailable = true;
49             }
50         }
51     }
52 
TearDown()53     void TearDown() override
54     {
55         SafeRelease(mDevice);
56         SafeRelease(mDeviceContext);
57 
58         OSWindow::Delete(&mOSWindow);
59 
60         if (mSurface != EGL_NO_SURFACE)
61         {
62             eglDestroySurface(mDisplay, mSurface);
63             mSurface = EGL_NO_SURFACE;
64         }
65 
66         if (mContext != EGL_NO_CONTEXT)
67         {
68             eglDestroyContext(mDisplay, mContext);
69             mContext = EGL_NO_CONTEXT;
70         }
71 
72         if (mDisplay != EGL_NO_DISPLAY)
73         {
74             eglTerminate(mDisplay);
75             mDisplay = EGL_NO_DISPLAY;
76         }
77     }
78 
CreateD3D11Device()79     void CreateD3D11Device()
80     {
81         ASSERT_TRUE(mD3D11Available);
82         ASSERT_EQ(nullptr, mDevice);  // The device shouldn't be created twice
83 
84         HRESULT hr =
85             mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, nullptr, 0,
86                                D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, &mDeviceContext);
87 
88         ASSERT_TRUE(SUCCEEDED(hr));
89     }
90 
InitializeDisplay()91     void InitializeDisplay()
92     {
93         EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
94                                    EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
95                                    EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
96                                    EGL_DONT_CARE,
97                                    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
98                                    EGL_DONT_CARE,
99                                    EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
100                                    EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
101                                    EGL_NONE};
102 
103         // Create an OS Window
104         mOSWindow = OSWindow::New();
105         mOSWindow->initialize("EGLSyncControlTest", 64, 64);
106         mOSWindow->setVisible(true);
107 
108         // Create an EGLDisplay using the EGLDevice
109         mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
110                                             reinterpret_cast<void *>(mOSWindow->getNativeDisplay()),
111                                             displayAttribs);
112         ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
113 
114         EGLint majorVersion, minorVersion;
115         ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE);
116     }
117 
CreateWindowSurface()118     void CreateWindowSurface()
119     {
120         eglBindAPI(EGL_OPENGL_ES_API);
121         ASSERT_EGL_SUCCESS();
122 
123         // Choose a config
124         const EGLint configAttributes[] = {EGL_NONE};
125 
126         EGLint configCount = 0;
127         ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount));
128 
129         const EGLint surfaceAttributes[] = {EGL_DIRECT_COMPOSITION_ANGLE, EGL_TRUE, EGL_NONE};
130 
131         // Create window surface
132         mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(),
133                                           surfaceAttributes);
134         if (mSurface == nullptr)
135         {
136             std::cout << "Unable to create window surface with Direct Composition" << std::endl;
137             return;
138         }
139 
140         mDirectCompositionSurfaceAvailable = true;
141 
142         // Create EGL context
143         EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
144 
145         mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
146         ASSERT_EGL_SUCCESS();
147 
148         // Make the surface current
149         eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
150         ASSERT_EGL_SUCCESS();
151     }
152 
153     bool mD3D11Available                       = false;
154     HMODULE mD3D11Module                       = nullptr;
155     PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice = nullptr;
156 
157     ID3D11Device *mDevice               = nullptr;
158     ID3D11DeviceContext *mDeviceContext = nullptr;
159     D3D_FEATURE_LEVEL mFeatureLevel;
160 
161     bool mDeviceCreationD3D11ExtAvailable = false;
162 
163     bool mDirectCompositionSurfaceAvailable = false;
164 
165     OSWindow *mOSWindow = nullptr;
166 
167     EGLDisplay mDisplay = EGL_NO_DISPLAY;
168     EGLSurface mSurface = EGL_NO_SURFACE;
169     EGLContext mContext = EGL_NO_CONTEXT;
170     EGLConfig mConfig   = 0;
171 };
172 
173 // Basic test for eglGetSyncValuesCHROMIUM extension. Verifies that eglGetSyncValuesCHROMIUM
174 // can be called on DX11 with direct composition and that it returns reasonable enough values.
TEST_F(EGLSyncControlTest,DISABLED_SyncValuesTest)175 TEST_F(EGLSyncControlTest, DISABLED_SyncValuesTest)
176 {
177     static const DWORD kPollInterval    = 10;
178     static const int kNumPollIterations = 100;
179 
180     if (!mD3D11Available)
181     {
182         std::cout << "D3D11 not available, skipping test" << std::endl;
183         return;
184     }
185 
186     CreateD3D11Device();
187     InitializeDisplay();
188     CreateWindowSurface();
189 
190     if (!mDirectCompositionSurfaceAvailable)
191     {
192         std::cout << "Direct Composition surface not available, skipping test" << std::endl;
193         return;
194     }
195 
196     const char *extensionString =
197         static_cast<const char *>(eglQueryString(mDisplay, EGL_EXTENSIONS));
198     ASSERT_TRUE(strstr(extensionString, "EGL_CHROMIUM_sync_control"));
199 
200     EGLuint64KHR ust = 0, msc = 0, sbc = 0;
201     // It appears there is a race condition so the very first call to eglGetSyncValuesCHROMIUM
202     // can fail within D3D with DXGI_ERROR_FRAME_STATISTICS_DISJOINT.
203     // Should that be handled inside eglGetSyncValuesCHROMIUM?
204     eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc);
205 
206     ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc));
207     // Initial msc and sbc value should be true. Initial ust value is unspecified.
208     ASSERT_EQ(0ull, msc);
209     ASSERT_EQ(0ull, sbc);
210 
211     // Perform some very basic rendering.
212     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
213     glClear(GL_COLOR_BUFFER_BIT);
214     ASSERT_GL_NO_ERROR();
215 
216     ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface));
217 
218     // Poll until sbc value increases. Normally it should change within 16-17 ms.
219     for (int i = 0; i < kNumPollIterations; i++)
220     {
221         ::Sleep(kPollInterval);
222         ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust, &msc, &sbc));
223         if (sbc > 0)
224             break;
225     }
226 
227     // sbc should change to 1. msc and ust to some non-zero values.
228     ASSERT_EQ(1ull, sbc);
229     ASSERT_GT(ust, 0ull);
230     ASSERT_GT(msc, 0ull);
231 
232     // Perform more rendering.
233     glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
234     glClear(GL_COLOR_BUFFER_BIT);
235     ASSERT_GL_NO_ERROR();
236 
237     ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface));
238 
239     // Poll until sbc value increases. Normally it should change within 16-17 ms.
240     EGLuint64KHR ust2 = 0, msc2 = 0, sbc2 = 0;
241     for (int i = 0; i < kNumPollIterations; i++)
242     {
243         ::Sleep(kPollInterval);
244         ASSERT_EGL_TRUE(eglGetSyncValuesCHROMIUM(mDisplay, mSurface, &ust2, &msc2, &sbc2));
245         if (sbc2 > sbc)
246             break;
247     }
248 
249     // sbc2 should be 2. msc2 and ust2 should be greater than previous msc and ust values.
250     ASSERT_EQ(2ull, sbc2);
251     ASSERT_GT(ust2, ust);
252     ASSERT_GT(msc2, msc);
253 }
254