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 "test_utils/gl_raii.h"
9 #include "util/EGLWindow.h"
10 #include "util/random_utils.h"
11 #include "util/test_utils.h"
12
13 using namespace angle;
14
15 class OcclusionQueriesTest : public ANGLETest
16 {
17 protected:
OcclusionQueriesTest()18 OcclusionQueriesTest() : mProgram(0), mRNG(1)
19 {
20 setWindowWidth(128);
21 setWindowHeight(128);
22 setConfigRedBits(8);
23 setConfigGreenBits(8);
24 setConfigBlueBits(8);
25 setConfigAlphaBits(8);
26 setConfigDepthBits(24);
27 }
28
testSetUp()29 void testSetUp() override
30 {
31 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
32 ASSERT_NE(0u, mProgram);
33 }
34
testTearDown()35 void testTearDown() override { glDeleteProgram(mProgram); }
36
37 GLuint mProgram;
38 RNG mRNG;
39 };
40
41 class OcclusionQueriesTestES3 : public OcclusionQueriesTest
42 {};
43
TEST_P(OcclusionQueriesTest,IsOccluded)44 TEST_P(OcclusionQueriesTest, IsOccluded)
45 {
46 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
47 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
48
49 glDepthMask(GL_TRUE);
50 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
51
52 // draw a quad at depth 0.3
53 glEnable(GL_DEPTH_TEST);
54 glUseProgram(mProgram);
55 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.3f);
56 glUseProgram(0);
57
58 EXPECT_GL_NO_ERROR();
59
60 GLQueryEXT query;
61 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
62 drawQuad(mProgram, essl1_shaders::PositionAttrib(),
63 0.8f); // this quad should be occluded by first quad
64 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
65
66 EXPECT_GL_NO_ERROR();
67
68 swapBuffers();
69
70 GLuint ready = GL_FALSE;
71 while (ready == GL_FALSE)
72 {
73 angle::Sleep(0);
74 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &ready);
75 }
76
77 GLuint result = GL_TRUE;
78 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
79
80 EXPECT_GL_NO_ERROR();
81
82 EXPECT_GL_FALSE(result);
83 }
84
TEST_P(OcclusionQueriesTest,IsNotOccluded)85 TEST_P(OcclusionQueriesTest, IsNotOccluded)
86 {
87 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
88 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
89
90 // TODO(syoussefi): Using render pass ops to clear the framebuffer attachment results in
91 // AMD/Windows misbehaving in this test. http://anglebug.com/3286
92 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
93
94 glDepthMask(GL_TRUE);
95 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
96
97 EXPECT_GL_NO_ERROR();
98
99 GLQueryEXT 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 EXPECT_GL_TRUE(result);
114 }
115
116 // Test that glClear should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,ClearNotCounted)117 TEST_P(OcclusionQueriesTest, ClearNotCounted)
118 {
119 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
120 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
121
122 // TODO(syoussefi): Using render pass ops to clear the framebuffer attachment results in
123 // AMD/Windows misbehaving in this test. http://anglebug.com/3286
124 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
125
126 // http://anglebug.com/4925
127 ANGLE_SKIP_TEST_IF(IsD3D11());
128
129 glDepthMask(GL_TRUE);
130 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
131
132 EXPECT_GL_NO_ERROR();
133
134 GLQueryEXT query[2];
135
136 // First query
137 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[0]);
138 // Full screen clear
139 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
140
141 // View port clear
142 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
143 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
144 glEnable(GL_SCISSOR_TEST);
145 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
146
147 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
148
149 EXPECT_GL_NO_ERROR();
150
151 // Second query
152 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[1]);
153
154 // View port clear
155 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
156
157 // View port clear
158 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
159 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
160 glEnable(GL_SCISSOR_TEST);
161 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
162
163 // this quad should not be occluded
164 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
165
166 // Clear again
167 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
168
169 // this quad should not be occluded
170 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 1.0);
171
172 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
173
174 EXPECT_GL_NO_ERROR();
175
176 swapBuffers();
177
178 GLuint result[2] = {GL_TRUE, GL_TRUE};
179 glGetQueryObjectuivEXT(query[0], GL_QUERY_RESULT_EXT,
180 &result[0]); // will block waiting for result
181 glGetQueryObjectuivEXT(query[1], GL_QUERY_RESULT_EXT,
182 &result[1]); // will block waiting for result
183 EXPECT_GL_NO_ERROR();
184
185 EXPECT_GL_FALSE(result[0]);
186 EXPECT_GL_TRUE(result[1]);
187 }
188
189 // Test that masked glClear should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,MaskedClearNotCounted)190 TEST_P(OcclusionQueriesTest, MaskedClearNotCounted)
191 {
192 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
193 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
194
195 // http://anglebug.com/4925
196 ANGLE_SKIP_TEST_IF(IsD3D());
197
198 GLQueryEXT query;
199
200 // Masked clear
201 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
202 glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE);
203 glClear(GL_COLOR_BUFFER_BIT);
204 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
205 EXPECT_GL_NO_ERROR();
206
207 swapBuffers();
208
209 GLuint result = GL_TRUE;
210 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
211 &result); // will block waiting for result
212 EXPECT_GL_NO_ERROR();
213
214 EXPECT_GL_FALSE(result);
215 }
216
217 // Test that copies should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,CopyNotCounted)218 TEST_P(OcclusionQueriesTest, CopyNotCounted)
219 {
220 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
221 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
222
223 // http://anglebug.com/4925
224 ANGLE_SKIP_TEST_IF(IsD3D());
225
226 GLQueryEXT query;
227
228 // Unrelated draw before the query starts.
229 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
230
231 // Copy to a texture with a different format from backbuffer
232 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
233 GLTexture tex;
234 glBindTexture(GL_TEXTURE_2D, tex);
235 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, getWindowWidth(), getWindowHeight(), 0);
236 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
237 EXPECT_GL_NO_ERROR();
238
239 swapBuffers();
240
241 GLuint result = GL_TRUE;
242 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
243 &result); // will block waiting for result
244 EXPECT_GL_NO_ERROR();
245
246 EXPECT_GL_FALSE(result);
247 }
248
249 // Test that blit should not be counted by occlusion query.
TEST_P(OcclusionQueriesTestES3,BlitNotCounted)250 TEST_P(OcclusionQueriesTestES3, BlitNotCounted)
251 {
252 // http://anglebug.com/4925
253 ANGLE_SKIP_TEST_IF(IsD3D11());
254
255 // http://anglebug.com/5101
256 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
257
258 constexpr GLuint kSize = 64;
259
260 GLFramebuffer srcFbo;
261 glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
262
263 GLTexture srcTex;
264 glBindTexture(GL_TEXTURE_2D, srcTex);
265 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
266 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTex, 0);
267
268 GLFramebuffer dstFbo;
269 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
270
271 GLTexture dstTex;
272 glBindTexture(GL_TEXTURE_2D, dstTex);
273 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kSize, kSize, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
274 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
275
276 GLQueryEXT query;
277
278 // Unrelated draw before the query starts.
279 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
280
281 // Blit flipped and with different formats.
282 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
283 glBlitFramebuffer(0, 0, 64, 64, 64, 64, 0, 0, GL_COLOR_BUFFER_BIT, GL_LINEAR);
284 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
285 EXPECT_GL_NO_ERROR();
286
287 swapBuffers();
288
289 GLuint result = GL_TRUE;
290 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
291 &result); // will block waiting for result
292 EXPECT_GL_NO_ERROR();
293
294 EXPECT_GL_FALSE(result);
295 }
296
297 // Test that multisampled-render-to-texture unresolve should not be counted by occlusion query.
TEST_P(OcclusionQueriesTestES3,UnresolveNotCounted)298 TEST_P(OcclusionQueriesTestES3, UnresolveNotCounted)
299 {
300 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
301
302 // http://anglebug.com/5086
303 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
304
305 constexpr GLuint kSize = 64;
306
307 GLFramebuffer fboMS;
308 glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
309
310 // Create multisampled framebuffer to draw into
311 GLTexture textureMS;
312 glBindTexture(GL_TEXTURE_2D, textureMS);
313 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
314 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
315 textureMS, 0, 4);
316
317 GLRenderbuffer depthMS;
318 glBindRenderbuffer(GL_RENDERBUFFER, depthMS);
319 glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, kSize, kSize);
320 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS);
321
322 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
323
324 // Draw red into the multisampled color buffer.
325 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
326 ASSERT_GL_NO_ERROR();
327
328 // Create a texture and copy into it, forcing a resolve of the color buffer.
329 GLTexture texture;
330 glBindTexture(GL_TEXTURE_2D, texture);
331 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
332
333 GLQueryEXT query;
334
335 // Make a draw call that will fail the depth test, and therefore shouldn't contribute to
336 // occlusion query.
337 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
338 glEnable(GL_DEPTH_TEST);
339 glDepthFunc(GL_NEVER);
340 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
341 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
342 EXPECT_GL_NO_ERROR();
343
344 swapBuffers();
345
346 GLuint result = GL_TRUE;
347 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
348 &result); // will block waiting for result
349 EXPECT_GL_NO_ERROR();
350
351 EXPECT_GL_FALSE(result);
352 }
353
354 // Test that changing framebuffers work
TEST_P(OcclusionQueriesTest,FramebufferBindingChange)355 TEST_P(OcclusionQueriesTest, FramebufferBindingChange)
356 {
357 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
358 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
359
360 constexpr GLsizei kSize = 4;
361
362 // Create two framebuffers, and make sure they are synced.
363 GLFramebuffer fbo[2];
364 GLTexture color[2];
365
366 for (size_t index = 0; index < 2; ++index)
367 {
368 glBindTexture(GL_TEXTURE_2D, color[index]);
369 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
370 nullptr);
371
372 glBindFramebuffer(GL_FRAMEBUFFER, fbo[index]);
373 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color[index],
374 0);
375
376 glClearColor(0, index, 1 - index, 1);
377 glClear(GL_COLOR_BUFFER_BIT);
378
379 EXPECT_PIXEL_COLOR_EQ(0, 0, index ? GLColor::green : GLColor::blue);
380 }
381 EXPECT_GL_NO_ERROR();
382
383 glViewport(0, 0, kSize, kSize);
384
385 // Start an occlusion query and issue a draw call to each framebuffer.
386 GLQueryEXT query;
387
388 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
389
390 for (size_t index = 0; index < 2; ++index)
391 {
392 glBindFramebuffer(GL_FRAMEBUFFER, fbo[index]);
393 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
394 }
395
396 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
397 EXPECT_GL_NO_ERROR();
398
399 GLuint result = GL_FALSE;
400 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
401 EXPECT_GL_NO_ERROR();
402
403 EXPECT_GL_TRUE(result);
404 }
405
406 // Test multiple occlusion queries.
TEST_P(OcclusionQueriesTest,MultiQueries)407 TEST_P(OcclusionQueriesTest, MultiQueries)
408 {
409 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
410 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
411
412 // TODO(syoussefi): Using render pass ops to clear the framebuffer attachment results in
413 // AMD/Windows misbehaving in this test. http://anglebug.com/3286
414 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
415
416 // http://anglebug.com/4925
417 ANGLE_SKIP_TEST_IF(IsOpenGL() || IsD3D11());
418
419 // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
420 ANGLE_SKIP_TEST_IF(IsOSX() && IsARM64() && IsDesktopOpenGL());
421
422 GLQueryEXT query[5];
423
424 // First query
425 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[0]);
426
427 EXPECT_GL_NO_ERROR();
428
429 glEnable(GL_DEPTH_TEST);
430 glDepthMask(GL_TRUE);
431 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
432
433 EXPECT_GL_NO_ERROR();
434
435 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
436
437 EXPECT_GL_NO_ERROR();
438
439 // Due to implementation might skip in-renderpass flush, we are using glFinish here to force a
440 // flush. A flush shound't clear the query result.
441 glFinish();
442
443 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
444 drawQuad(mProgram, essl1_shaders::PositionAttrib(), -2, 0.25f); // this quad should be occluded
445 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
446 // First query ends
447
448 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f,
449 0.25f); // this quad should not be occluded
450
451 // Second query
452 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[1]);
453 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
454 0.25f); // this quad should be occluded
455 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
456
457 // Third query
458 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[2]);
459 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
460 0.5f); // this quad should not be occluded
461 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
462 // ------------
463 glFinish();
464
465 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
466 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
467 glEnable(GL_SCISSOR_TEST);
468 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
469 0.5f); // this quad should not be occluded
470
471 // Fourth query: begin query then end then begin again
472 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[3]);
473 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
474 1); // this quad should not be occluded
475 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
476 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[3]);
477 EXPECT_GL_NO_ERROR();
478 // glClear should not be counted toward query);
479 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
480 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
481
482 // Fifth query spans across frames
483 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[4]);
484 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f,
485 0.25f); // this quad should not be occluded
486
487 swapBuffers();
488
489 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
490
491 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
492 0.5f); // this quad should not be occluded
493 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
494
495 GLuint result = GL_TRUE;
496 glGetQueryObjectuivEXT(query[0], GL_QUERY_RESULT_EXT,
497 &result); // will block waiting for result
498 EXPECT_GL_NO_ERROR();
499 EXPECT_GL_TRUE(result);
500
501 glGetQueryObjectuivEXT(query[1], GL_QUERY_RESULT_EXT,
502 &result); // will block waiting for result
503 EXPECT_GL_NO_ERROR();
504 EXPECT_GL_FALSE(result);
505
506 glGetQueryObjectuivEXT(query[2], GL_QUERY_RESULT_EXT,
507 &result); // will block waiting for result
508 EXPECT_GL_NO_ERROR();
509 EXPECT_GL_TRUE(result);
510
511 glGetQueryObjectuivEXT(query[3], GL_QUERY_RESULT_EXT,
512 &result); // will block waiting for result
513 EXPECT_GL_NO_ERROR();
514 EXPECT_GL_FALSE(result);
515
516 glGetQueryObjectuivEXT(query[4], GL_QUERY_RESULT_EXT,
517 &result); // will block waiting for result
518 EXPECT_GL_NO_ERROR();
519 EXPECT_GL_TRUE(result);
520 }
521
TEST_P(OcclusionQueriesTest,Errors)522 TEST_P(OcclusionQueriesTest, Errors)
523 {
524 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
525 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
526
527 glDepthMask(GL_TRUE);
528 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
529
530 EXPECT_GL_NO_ERROR();
531
532 GLuint query = 0;
533 GLuint query2 = 0;
534 glGenQueriesEXT(1, &query);
535
536 EXPECT_GL_FALSE(glIsQueryEXT(query));
537 EXPECT_GL_FALSE(glIsQueryEXT(query2));
538
539 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0); // can't pass 0 as query id
540 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
541
542 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
543 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
544 query2); // can't initiate a query while one's already active
545 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
546
547 EXPECT_GL_TRUE(glIsQueryEXT(query));
548 EXPECT_GL_FALSE(glIsQueryEXT(query2)); // have not called begin
549
550 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
551 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // no active query for this target
552 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
553 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
554
555 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
556 query); // can't begin a query as a different type than previously used
557 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
558
559 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
560 query2); // have to call genqueries first
561 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
562
563 glGenQueriesEXT(1, &query2);
564 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, query2); // should be ok now
565 EXPECT_GL_TRUE(glIsQueryEXT(query2));
566
567 drawQuad(mProgram, essl1_shaders::PositionAttrib(),
568 0.3f); // this should draw in front of other quad
569 glDeleteQueriesEXT(1, &query2); // should delete when query becomes inactive
570 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // should not incur error; should delete
571 // query + 1 at end of execution.
572 EXPECT_GL_NO_ERROR();
573
574 swapBuffers();
575
576 EXPECT_GL_NO_ERROR();
577
578 GLuint ready = GL_FALSE;
579 glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT,
580 &ready); // this query is now deleted
581 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
582
583 EXPECT_GL_NO_ERROR();
584 }
585
586 // Test that running multiple simultaneous queries from multiple EGL contexts returns the correct
587 // result for each query. Helps expose bugs in ANGLE's virtual contexts.
TEST_P(OcclusionQueriesTest,MultiContext)588 TEST_P(OcclusionQueriesTest, MultiContext)
589 {
590 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
591 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
592
593 // TODO(cwallez@chromium.org): Suppression for http://anglebug.com/3080
594 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan());
595
596 // Test skipped because the D3D backends cannot support simultaneous queries on multiple
597 // contexts yet.
598 ANGLE_SKIP_TEST_IF(GetParam() == ES2_D3D9() || GetParam() == ES2_D3D11() ||
599 GetParam() == ES3_D3D11());
600
601 glDepthMask(GL_TRUE);
602 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
603
604 // draw a quad at depth 0.5
605 glEnable(GL_DEPTH_TEST);
606 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
607
608 EGLWindow *window = getEGLWindow();
609
610 EGLDisplay display = window->getDisplay();
611 EGLConfig config = window->getConfig();
612 EGLSurface surface = window->getSurface();
613
614 EGLint contextAttributes[] = {
615 EGL_CONTEXT_MAJOR_VERSION_KHR,
616 GetParam().majorVersion,
617 EGL_CONTEXT_MINOR_VERSION_KHR,
618 GetParam().minorVersion,
619 EGL_NONE,
620 };
621
622 const size_t passCount = 5;
623 struct ContextInfo
624 {
625 EGLContext context;
626 GLuint program;
627 GLuint query;
628 bool visiblePasses[passCount];
629 bool shouldPass;
630 };
631
632 ContextInfo contexts[] = {
633 {
634 EGL_NO_CONTEXT,
635 0,
636 0,
637 {false, false, false, false, false},
638 false,
639 },
640 {
641 EGL_NO_CONTEXT,
642 0,
643 0,
644 {false, true, false, true, false},
645 true,
646 },
647 {
648 EGL_NO_CONTEXT,
649 0,
650 0,
651 {false, false, false, false, false},
652 false,
653 },
654 {
655 EGL_NO_CONTEXT,
656 0,
657 0,
658 {true, true, false, true, true},
659 true,
660 },
661 {
662 EGL_NO_CONTEXT,
663 0,
664 0,
665 {false, true, true, true, true},
666 true,
667 },
668 {
669 EGL_NO_CONTEXT,
670 0,
671 0,
672 {true, false, false, true, false},
673 true,
674 },
675 {
676 EGL_NO_CONTEXT,
677 0,
678 0,
679 {false, false, false, false, false},
680 false,
681 },
682 {
683 EGL_NO_CONTEXT,
684 0,
685 0,
686 {false, false, false, false, false},
687 false,
688 },
689 };
690
691 for (auto &context : contexts)
692 {
693 context.context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
694 ASSERT_NE(context.context, EGL_NO_CONTEXT);
695
696 eglMakeCurrent(display, surface, surface, context.context);
697
698 context.program = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
699 ASSERT_NE(context.program, 0u);
700
701 glDepthMask(GL_FALSE);
702 glEnable(GL_DEPTH_TEST);
703
704 glGenQueriesEXT(1, &context.query);
705 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, context.query);
706
707 ASSERT_GL_NO_ERROR();
708 }
709
710 for (size_t pass = 0; pass < passCount; pass++)
711 {
712 for (const auto &context : contexts)
713 {
714 eglMakeCurrent(display, surface, surface, context.context);
715
716 float depth = context.visiblePasses[pass] ? mRNG.randomFloatBetween(0.0f, 0.4f)
717 : mRNG.randomFloatBetween(0.6f, 1.0f);
718 drawQuad(context.program, essl1_shaders::PositionAttrib(), depth);
719
720 EXPECT_GL_NO_ERROR();
721 }
722 }
723
724 for (const auto &context : contexts)
725 {
726 eglMakeCurrent(display, surface, surface, context.context);
727 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
728
729 GLuint result = GL_TRUE;
730 glGetQueryObjectuivEXT(context.query, GL_QUERY_RESULT_EXT, &result);
731
732 EXPECT_GL_NO_ERROR();
733
734 GLuint expectation = context.shouldPass ? GL_TRUE : GL_FALSE;
735 EXPECT_EQ(expectation, result);
736 }
737
738 eglMakeCurrent(display, surface, surface, window->getContext());
739
740 for (auto &context : contexts)
741 {
742 eglDestroyContext(display, context.context);
743 context.context = EGL_NO_CONTEXT;
744 }
745 }
746
747 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(OcclusionQueriesTest);
748
749 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OcclusionQueriesTestES3);
750 ANGLE_INSTANTIATE_TEST_ES3(OcclusionQueriesTestES3);
751