1 //
2 // Copyright 2019 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 // EGLSyncTest.cpp:
7 // Tests of EGL_KHR_fence_sync and EGL_KHR_wait_sync extensions.
8
9 #include <gtest/gtest.h>
10
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/angle_test_configs.h"
13 #include "util/EGLWindow.h"
14
15 using namespace angle;
16
17 class EGLSyncTest : public ANGLETest
18 {
19 protected:
hasFenceSyncExtension() const20 bool hasFenceSyncExtension() const
21 {
22 return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_fence_sync");
23 }
hasWaitSyncExtension() const24 bool hasWaitSyncExtension() const
25 {
26 return hasFenceSyncExtension() &&
27 IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_wait_sync");
28 }
hasGLSyncExtension() const29 bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); }
30 };
31
32 // Test error cases for all EGL_KHR_fence_sync functions
TEST_P(EGLSyncTest,FenceSyncErrors)33 TEST_P(EGLSyncTest, FenceSyncErrors)
34 {
35 ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
36
37 EGLDisplay display = getEGLWindow()->getDisplay();
38
39 // If the client API doesn't have the necessary extension, test that sync creation fails and
40 // ignore the rest of the tests.
41 if (!hasGLSyncExtension())
42 {
43 EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
44 EXPECT_EGL_ERROR(EGL_BAD_MATCH);
45 }
46
47 ANGLE_SKIP_TEST_IF(!hasGLSyncExtension());
48
49 EGLContext context = eglGetCurrentContext();
50 EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
51 EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
52
53 EXPECT_NE(context, EGL_NO_CONTEXT);
54 EXPECT_NE(drawSurface, EGL_NO_SURFACE);
55 EXPECT_NE(readSurface, EGL_NO_SURFACE);
56
57 // CreateSync with no attribute shouldn't cause an error
58 EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
59 EXPECT_NE(sync, EGL_NO_SYNC_KHR);
60
61 EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
62
63 // CreateSync with empty attribute shouldn't cause an error
64 const EGLint emptyAttributes[] = {EGL_NONE};
65 sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, emptyAttributes);
66 EXPECT_NE(sync, EGL_NO_SYNC_KHR);
67
68 // DestroySync generates BAD_PARAMETER if the sync is not valid
69 EXPECT_EGL_FALSE(eglDestroySyncKHR(display, reinterpret_cast<EGLSyncKHR>(20)));
70 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
71
72 // CreateSync generates BAD_DISPLAY if display is not valid
73 EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(EGL_NO_DISPLAY, EGL_SYNC_FENCE_KHR, nullptr));
74 EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
75
76 // CreateSync generates BAD_ATTRIBUTE if attribute is neither nullptr nor empty.
77 const EGLint nonEmptyAttributes[] = {
78 EGL_CL_EVENT_HANDLE,
79 0,
80 EGL_NONE,
81 };
82 EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nonEmptyAttributes));
83 EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
84
85 // CreateSync generates BAD_ATTRIBUTE if type is not valid
86 EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, 0, nullptr));
87 EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
88
89 // CreateSync generates BAD_MATCH if no context is current
90 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
91 EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr));
92 EXPECT_EGL_ERROR(EGL_BAD_MATCH);
93 eglMakeCurrent(display, drawSurface, readSurface, context);
94
95 // ClientWaitSync generates EGL_BAD_PARAMETER if the sync object is not valid
96 EXPECT_EGL_FALSE(eglClientWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(30), 0, 0));
97 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
98
99 // GetSyncAttrib generates EGL_BAD_PARAMETER if the sync object is not valid, and value is not
100 // modified
101 constexpr EGLint kSentinelAttribValue = 123456789;
102 EGLint attribValue = kSentinelAttribValue;
103 EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, reinterpret_cast<EGLSyncKHR>(40),
104 EGL_SYNC_TYPE_KHR, &attribValue));
105 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
106 EXPECT_EQ(attribValue, kSentinelAttribValue);
107
108 // GetSyncAttrib generates EGL_BAD_ATTRIBUTE if the attribute is not valid, and value is not
109 // modified
110 EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, sync, EGL_CL_EVENT_HANDLE, &attribValue));
111 EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
112 EXPECT_EQ(attribValue, kSentinelAttribValue);
113
114 // GetSyncAttrib generates EGL_BAD_MATCH if the attribute is valid for sync, but not the
115 // particular sync type. We don't have such a case at the moment.
116
117 EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
118 }
119
120 // Test error cases for all EGL_KHR_wait_sync functions
TEST_P(EGLSyncTest,WaitSyncErrors)121 TEST_P(EGLSyncTest, WaitSyncErrors)
122 {
123 // The client API that shows support for eglWaitSyncKHR is the same as the one required for
124 // eglCreateSyncKHR. As such, there is no way to create a sync and not be able to wait on it.
125 // This would have created an EGL_BAD_MATCH error.
126 ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
127
128 EGLDisplay display = getEGLWindow()->getDisplay();
129 EGLContext context = eglGetCurrentContext();
130 EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
131 EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
132
133 EXPECT_NE(context, EGL_NO_CONTEXT);
134 EXPECT_NE(drawSurface, EGL_NO_SURFACE);
135 EXPECT_NE(readSurface, EGL_NO_SURFACE);
136
137 EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
138 EXPECT_NE(sync, EGL_NO_SYNC_KHR);
139
140 // WaitSync generates BAD_MATCH if no context is current
141 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
142 EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 0));
143 EXPECT_EGL_ERROR(EGL_BAD_MATCH);
144 eglMakeCurrent(display, drawSurface, readSurface, context);
145
146 // WaitSync generates BAD_PARAMETER if the sync is not valid
147 EXPECT_EGL_FALSE(eglWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(20), 0));
148 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
149
150 // WaitSync generates BAD_PARAMETER if flags is non-zero
151 EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 1));
152 EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
153
154 EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
155 }
156
157 // Test usage of eglGetSyncAttribKHR
TEST_P(EGLSyncTest,GetSyncAttrib)158 TEST_P(EGLSyncTest, GetSyncAttrib)
159 {
160 ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
161
162 EGLDisplay display = getEGLWindow()->getDisplay();
163
164 EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
165 EXPECT_NE(sync, EGL_NO_SYNC_KHR);
166
167 // Fence sync attributes are:
168 //
169 // EGL_SYNC_TYPE_KHR: EGL_SYNC_FENCE_KHR
170 // EGL_SYNC_STATUS_KHR: EGL_UNSIGNALED_KHR or EGL_SIGNALED_KHR
171 // EGL_SYNC_CONDITION_KHR: EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR
172
173 constexpr EGLint kSentinelAttribValue = 123456789;
174 EGLint attribValue = kSentinelAttribValue;
175 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_TYPE_KHR, &attribValue));
176 EXPECT_EQ(attribValue, EGL_SYNC_FENCE_KHR);
177
178 attribValue = kSentinelAttribValue;
179 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_CONDITION_KHR, &attribValue));
180 EXPECT_EQ(attribValue, EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR);
181
182 attribValue = kSentinelAttribValue;
183 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &attribValue));
184
185 // Hack around EXPECT_* not having an "either this or that" variant:
186 if (attribValue != EGL_SIGNALED_KHR)
187 {
188 EXPECT_EQ(attribValue, EGL_UNSIGNALED_KHR);
189 }
190
191 EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
192 }
193
194 // Test that basic usage works and doesn't generate errors or crash
TEST_P(EGLSyncTest,BasicOperations)195 TEST_P(EGLSyncTest, BasicOperations)
196 {
197 ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
198
199 EGLDisplay display = getEGLWindow()->getDisplay();
200
201 EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
202 EXPECT_NE(sync, EGL_NO_SYNC_KHR);
203
204 glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
205
206 glClear(GL_COLOR_BUFFER_BIT);
207 EXPECT_EGL_TRUE(eglWaitSyncKHR(display, sync, 0));
208
209 glFlush();
210
211 EGLint value = 0;
212 unsigned int loopCount = 0;
213
214 // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
215 while (value != EGL_SIGNALED_KHR && loopCount <= 1000000)
216 {
217 loopCount++;
218 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value));
219 }
220
221 ASSERT_EQ(value, EGL_SIGNALED_KHR);
222
223 for (size_t i = 0; i < 20; i++)
224 {
225 glClear(GL_COLOR_BUFFER_BIT);
226 EXPECT_EQ(
227 EGL_CONDITION_SATISFIED_KHR,
228 eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
229 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value));
230 EXPECT_EQ(value, EGL_SIGNALED_KHR);
231 }
232
233 EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
234 }
235
236 // Test eglWaitNative api
TEST_P(EGLSyncTest,WaitNative)237 TEST_P(EGLSyncTest, WaitNative)
238 {
239 // Clear to red color
240 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
241
242 glClear(GL_COLOR_BUFFER_BIT);
243 EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE));
244 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
245 }
246
247 ANGLE_INSTANTIATE_TEST(EGLSyncTest,
248 ES2_D3D9(),
249 ES2_D3D11(),
250 ES3_D3D11(),
251 ES2_OPENGL(),
252 ES3_OPENGL(),
253 ES2_OPENGLES(),
254 ES3_OPENGLES(),
255 ES2_VULKAN(),
256 ES3_VULKAN());
257