1 //
2 // Copyright 2015 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 #include "test_utils/ANGLETest.h"
8 #include "util/EGLWindow.h"
9 #include "util/random_utils.h"
10 #include "util/test_utils.h"
11
12 using namespace angle;
13
14 class OcclusionQueriesTest : public ANGLETest
15 {
16 protected:
OcclusionQueriesTest()17 OcclusionQueriesTest() : mProgram(0), mRNG(1)
18 {
19 setWindowWidth(128);
20 setWindowHeight(128);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 setConfigDepthBits(24);
26 }
27
testSetUp()28 void testSetUp() override
29 {
30 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
31 ASSERT_NE(0u, mProgram);
32 }
33
testTearDown()34 void testTearDown() override { glDeleteProgram(mProgram); }
35
36 GLuint mProgram;
37 RNG mRNG;
38 };
39
TEST_P(OcclusionQueriesTest,IsOccluded)40 TEST_P(OcclusionQueriesTest, IsOccluded)
41 {
42 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
43 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
44
45 glDepthMask(GL_TRUE);
46 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
47
48 // draw a quad at depth 0.3
49 glEnable(GL_DEPTH_TEST);
50 glUseProgram(mProgram);
51 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.3f);
52 glUseProgram(0);
53
54 EXPECT_GL_NO_ERROR();
55
56 GLuint query = 0;
57 glGenQueriesEXT(1, &query);
58 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
59 drawQuad(mProgram, essl1_shaders::PositionAttrib(),
60 0.8f); // this quad should be occluded by first quad
61 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
62
63 EXPECT_GL_NO_ERROR();
64
65 swapBuffers();
66
67 GLuint ready = GL_FALSE;
68 while (ready == GL_FALSE)
69 {
70 angle::Sleep(0);
71 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
72 }
73
74 GLuint result = GL_TRUE;
75 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
76
77 EXPECT_GL_NO_ERROR();
78
79 glDeleteQueriesEXT(1, &query);
80
81 EXPECT_GL_FALSE(result);
82 }
83
TEST_P(OcclusionQueriesTest,IsNotOccluded)84 TEST_P(OcclusionQueriesTest, IsNotOccluded)
85 {
86 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
87 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
88
89 // TODO(syoussefi): Using render pass ops to clear the framebuffer attachment results in
90 // AMD/Windows misbehaving in this test. http://anglebug.com/3286
91 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
92
93 glDepthMask(GL_TRUE);
94 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
95
96 EXPECT_GL_NO_ERROR();
97
98 GLuint query = 0;
99 glGenQueriesEXT(1, &query);
100 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
101 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
102 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
103
104 EXPECT_GL_NO_ERROR();
105
106 swapBuffers();
107
108 GLuint result = GL_TRUE;
109 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result); // will block waiting for result
110
111 EXPECT_GL_NO_ERROR();
112
113 glDeleteQueriesEXT(1, &query);
114
115 EXPECT_GL_TRUE(result);
116 }
117
TEST_P(OcclusionQueriesTest,Errors)118 TEST_P(OcclusionQueriesTest, Errors)
119 {
120 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
121 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
122
123 glDepthMask(GL_TRUE);
124 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
125
126 EXPECT_GL_NO_ERROR();
127
128 GLuint query = 0;
129 GLuint query2 = 0;
130 glGenQueriesEXT(1, &query);
131
132 EXPECT_GL_FALSE(glIsQueryEXT(query));
133 EXPECT_GL_FALSE(glIsQueryEXT(query2));
134
135 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0); // can't pass 0 as query id
136 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
137
138 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
139 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
140 query2); // can't initiate a query while one's already active
141 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
142
143 EXPECT_GL_TRUE(glIsQueryEXT(query));
144 EXPECT_GL_FALSE(glIsQueryEXT(query2)); // have not called begin
145
146 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
147 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // no active query for this target
148 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
149 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
150
151 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
152 query); // can't begin a query as a different type than previously used
153 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
154
155 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
156 query2); // have to call genqueries first
157 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
158
159 glGenQueriesEXT(1, &query2);
160 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, query2); // should be ok now
161 EXPECT_GL_TRUE(glIsQueryEXT(query2));
162
163 drawQuad(mProgram, essl1_shaders::PositionAttrib(),
164 0.3f); // this should draw in front of other quad
165 glDeleteQueriesEXT(1, &query2); // should delete when query becomes inactive
166 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // should not incur error; should delete
167 // query + 1 at end of execution.
168 EXPECT_GL_NO_ERROR();
169
170 swapBuffers();
171
172 EXPECT_GL_NO_ERROR();
173
174 GLuint ready = GL_FALSE;
175 glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT,
176 &ready); // this query is now deleted
177 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
178
179 EXPECT_GL_NO_ERROR();
180 }
181
182 // Test that running multiple simultaneous queries from multiple EGL contexts returns the correct
183 // result for each query. Helps expose bugs in ANGLE's virtual contexts.
TEST_P(OcclusionQueriesTest,MultiContext)184 TEST_P(OcclusionQueriesTest, MultiContext)
185 {
186 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
187 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
188
189 // TODO(cwallez@chromium.org): Suppression for http://anglebug.com/3080
190 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan());
191
192 // Test skipped because the D3D backends cannot support simultaneous queries on multiple
193 // contexts yet. Same with the Vulkan backend.
194 ANGLE_SKIP_TEST_IF(GetParam() == ES2_D3D9() || GetParam() == ES2_D3D11() ||
195 GetParam() == ES3_D3D11() || GetParam() == ES2_VULKAN());
196
197 // http://anglebug.com/4092
198 ANGLE_SKIP_TEST_IF(IsVulkan());
199
200 glDepthMask(GL_TRUE);
201 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
202
203 // draw a quad at depth 0.5
204 glEnable(GL_DEPTH_TEST);
205 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
206
207 EGLWindow *window = getEGLWindow();
208
209 EGLDisplay display = window->getDisplay();
210 EGLConfig config = window->getConfig();
211 EGLSurface surface = window->getSurface();
212
213 EGLint contextAttributes[] = {
214 EGL_CONTEXT_MAJOR_VERSION_KHR,
215 GetParam().majorVersion,
216 EGL_CONTEXT_MINOR_VERSION_KHR,
217 GetParam().minorVersion,
218 EGL_NONE,
219 };
220
221 const size_t passCount = 5;
222 struct ContextInfo
223 {
224 EGLContext context;
225 GLuint program;
226 GLuint query;
227 bool visiblePasses[passCount];
228 bool shouldPass;
229 };
230
231 ContextInfo contexts[] = {
232 {
233 EGL_NO_CONTEXT,
234 0,
235 0,
236 {false, false, false, false, false},
237 false,
238 },
239 {
240 EGL_NO_CONTEXT,
241 0,
242 0,
243 {false, true, false, true, false},
244 true,
245 },
246 {
247 EGL_NO_CONTEXT,
248 0,
249 0,
250 {false, false, false, false, false},
251 false,
252 },
253 {
254 EGL_NO_CONTEXT,
255 0,
256 0,
257 {true, true, false, true, true},
258 true,
259 },
260 {
261 EGL_NO_CONTEXT,
262 0,
263 0,
264 {false, true, true, true, true},
265 true,
266 },
267 {
268 EGL_NO_CONTEXT,
269 0,
270 0,
271 {true, false, false, true, false},
272 true,
273 },
274 {
275 EGL_NO_CONTEXT,
276 0,
277 0,
278 {false, false, false, false, false},
279 false,
280 },
281 {
282 EGL_NO_CONTEXT,
283 0,
284 0,
285 {false, false, false, false, false},
286 false,
287 },
288 };
289
290 for (auto &context : contexts)
291 {
292 context.context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
293 ASSERT_NE(context.context, EGL_NO_CONTEXT);
294
295 eglMakeCurrent(display, surface, surface, context.context);
296
297 context.program = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
298 ASSERT_NE(context.program, 0u);
299
300 glDepthMask(GL_FALSE);
301 glEnable(GL_DEPTH_TEST);
302
303 glGenQueriesEXT(1, &context.query);
304 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, context.query);
305
306 ASSERT_GL_NO_ERROR();
307 }
308
309 for (size_t pass = 0; pass < passCount; pass++)
310 {
311 for (const auto &context : contexts)
312 {
313 eglMakeCurrent(display, surface, surface, context.context);
314
315 float depth = context.visiblePasses[pass] ? mRNG.randomFloatBetween(0.0f, 0.4f)
316 : mRNG.randomFloatBetween(0.6f, 1.0f);
317 drawQuad(context.program, essl1_shaders::PositionAttrib(), depth);
318
319 EXPECT_GL_NO_ERROR();
320 }
321 }
322
323 for (const auto &context : contexts)
324 {
325 eglMakeCurrent(display, surface, surface, context.context);
326 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
327
328 GLuint result = GL_TRUE;
329 glGetQueryObjectuivEXT(context.query, GL_QUERY_RESULT_EXT, &result);
330
331 EXPECT_GL_NO_ERROR();
332
333 GLuint expectation = context.shouldPass ? GL_TRUE : GL_FALSE;
334 EXPECT_EQ(expectation, result);
335 }
336
337 eglMakeCurrent(display, surface, surface, window->getContext());
338
339 for (auto &context : contexts)
340 {
341 eglDestroyContext(display, context.context);
342 context.context = EGL_NO_CONTEXT;
343 }
344 }
345
346 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
347 // tests should be run against.
348 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(OcclusionQueriesTest);
349