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