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 glDepthMask(GL_TRUE);
91 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
92
93 EXPECT_GL_NO_ERROR();
94
95 GLQueryEXT query;
96 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
97 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
98 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
99
100 EXPECT_GL_NO_ERROR();
101
102 swapBuffers();
103
104 GLuint result = GL_TRUE;
105 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result); // will block waiting for result
106
107 EXPECT_GL_NO_ERROR();
108
109 EXPECT_GL_TRUE(result);
110 }
111
112 // Test that glClear should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,ClearNotCounted)113 TEST_P(OcclusionQueriesTest, ClearNotCounted)
114 {
115 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
116 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
117
118 // http://anglebug.com/4925
119 ANGLE_SKIP_TEST_IF(IsD3D11());
120
121 glDepthMask(GL_TRUE);
122 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
123
124 EXPECT_GL_NO_ERROR();
125
126 GLQueryEXT query[2];
127
128 // First query
129 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[0]);
130 // Full screen clear
131 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
132
133 // View port clear
134 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
135 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
136 glEnable(GL_SCISSOR_TEST);
137 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
138
139 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
140
141 EXPECT_GL_NO_ERROR();
142
143 // Second query
144 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[1]);
145
146 // View port clear
147 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
148
149 // View port clear
150 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
151 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
152 glEnable(GL_SCISSOR_TEST);
153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
154
155 // this quad should not be occluded
156 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
157
158 // Clear again
159 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
160
161 // this quad should not be occluded
162 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 1.0);
163
164 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
165
166 EXPECT_GL_NO_ERROR();
167
168 swapBuffers();
169
170 GLuint result[2] = {GL_TRUE, GL_TRUE};
171 glGetQueryObjectuivEXT(query[0], GL_QUERY_RESULT_EXT,
172 &result[0]); // will block waiting for result
173 glGetQueryObjectuivEXT(query[1], GL_QUERY_RESULT_EXT,
174 &result[1]); // will block waiting for result
175 EXPECT_GL_NO_ERROR();
176
177 EXPECT_GL_FALSE(result[0]);
178 EXPECT_GL_TRUE(result[1]);
179 }
180
181 // Test that masked glClear should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,MaskedClearNotCounted)182 TEST_P(OcclusionQueriesTest, MaskedClearNotCounted)
183 {
184 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
185 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
186
187 // http://anglebug.com/4925
188 ANGLE_SKIP_TEST_IF(IsD3D());
189
190 GLQueryEXT query;
191
192 // Masked clear
193 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
194 glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE);
195 glClear(GL_COLOR_BUFFER_BIT);
196 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
197 EXPECT_GL_NO_ERROR();
198
199 swapBuffers();
200
201 GLuint result = GL_TRUE;
202 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
203 &result); // will block waiting for result
204 EXPECT_GL_NO_ERROR();
205
206 EXPECT_GL_FALSE(result);
207 }
208
209 // Test that copies should not be counted by occlusion query.
TEST_P(OcclusionQueriesTest,CopyNotCounted)210 TEST_P(OcclusionQueriesTest, CopyNotCounted)
211 {
212 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
213 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
214
215 // http://anglebug.com/4925
216 ANGLE_SKIP_TEST_IF(IsD3D());
217
218 GLQueryEXT query;
219
220 // Unrelated draw before the query starts.
221 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
222
223 // Copy to a texture with a different format from backbuffer
224 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
225 GLTexture tex;
226 glBindTexture(GL_TEXTURE_2D, tex);
227 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, getWindowWidth(), getWindowHeight(), 0);
228 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
229 EXPECT_GL_NO_ERROR();
230
231 swapBuffers();
232
233 GLuint result = GL_TRUE;
234 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
235 &result); // will block waiting for result
236 EXPECT_GL_NO_ERROR();
237
238 EXPECT_GL_FALSE(result);
239 }
240
241 // Test that blit should not be counted by occlusion query.
TEST_P(OcclusionQueriesTestES3,BlitNotCounted)242 TEST_P(OcclusionQueriesTestES3, BlitNotCounted)
243 {
244 // http://anglebug.com/4925
245 ANGLE_SKIP_TEST_IF(IsD3D11());
246
247 // http://anglebug.com/5101
248 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
249
250 constexpr GLuint kSize = 64;
251
252 GLFramebuffer srcFbo;
253 glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
254
255 GLTexture srcTex;
256 glBindTexture(GL_TEXTURE_2D, srcTex);
257 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
258 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTex, 0);
259
260 GLFramebuffer dstFbo;
261 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
262
263 GLTexture dstTex;
264 glBindTexture(GL_TEXTURE_2D, dstTex);
265 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kSize, kSize, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
266 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
267
268 GLQueryEXT query;
269
270 // Unrelated draw before the query starts.
271 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
272
273 // Blit flipped and with different formats.
274 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
275 glBlitFramebuffer(0, 0, 64, 64, 64, 64, 0, 0, GL_COLOR_BUFFER_BIT, GL_LINEAR);
276 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
277 EXPECT_GL_NO_ERROR();
278
279 swapBuffers();
280
281 GLuint result = GL_TRUE;
282 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
283 &result); // will block waiting for result
284 EXPECT_GL_NO_ERROR();
285
286 EXPECT_GL_FALSE(result);
287 }
288
289 // Test that multisampled-render-to-texture unresolve should not be counted by occlusion query.
TEST_P(OcclusionQueriesTestES3,UnresolveNotCounted)290 TEST_P(OcclusionQueriesTestES3, UnresolveNotCounted)
291 {
292 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
293
294 // http://anglebug.com/5086
295 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
296
297 constexpr GLuint kSize = 64;
298
299 GLFramebuffer fboMS;
300 glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
301
302 // Create multisampled framebuffer to draw into
303 GLTexture textureMS;
304 glBindTexture(GL_TEXTURE_2D, textureMS);
305 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
306 glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
307 textureMS, 0, 4);
308
309 GLRenderbuffer depthMS;
310 glBindRenderbuffer(GL_RENDERBUFFER, depthMS);
311 glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, kSize, kSize);
312 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthMS);
313
314 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
315
316 // Draw red into the multisampled color buffer.
317 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
318 ASSERT_GL_NO_ERROR();
319
320 // Create a texture and copy into it, forcing a resolve of the color buffer.
321 GLTexture texture;
322 glBindTexture(GL_TEXTURE_2D, texture);
323 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
324
325 GLQueryEXT query;
326
327 // Make a draw call that will fail the depth test, and therefore shouldn't contribute to
328 // occlusion query.
329 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
330 glEnable(GL_DEPTH_TEST);
331 glDepthFunc(GL_NEVER);
332 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f, 0.5f);
333 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
334 EXPECT_GL_NO_ERROR();
335
336 swapBuffers();
337
338 GLuint result = GL_TRUE;
339 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT,
340 &result); // will block waiting for result
341 EXPECT_GL_NO_ERROR();
342
343 EXPECT_GL_FALSE(result);
344 }
345
346 // Test that changing framebuffers work
TEST_P(OcclusionQueriesTest,FramebufferBindingChange)347 TEST_P(OcclusionQueriesTest, FramebufferBindingChange)
348 {
349 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
350 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
351
352 constexpr GLsizei kSize = 4;
353
354 // Create two framebuffers, and make sure they are synced.
355 GLFramebuffer fbo[2];
356 GLTexture color[2];
357
358 for (size_t index = 0; index < 2; ++index)
359 {
360 glBindTexture(GL_TEXTURE_2D, color[index]);
361 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
362 nullptr);
363
364 glBindFramebuffer(GL_FRAMEBUFFER, fbo[index]);
365 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color[index],
366 0);
367
368 glClearColor(0, index, 1 - index, 1);
369 glClear(GL_COLOR_BUFFER_BIT);
370
371 EXPECT_PIXEL_COLOR_EQ(0, 0, index ? GLColor::green : GLColor::blue);
372 }
373 EXPECT_GL_NO_ERROR();
374
375 glViewport(0, 0, kSize, kSize);
376
377 // Start an occlusion query and issue a draw call to each framebuffer.
378 GLQueryEXT query;
379
380 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
381
382 for (size_t index = 0; index < 2; ++index)
383 {
384 glBindFramebuffer(GL_FRAMEBUFFER, fbo[index]);
385 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
386 }
387
388 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
389 EXPECT_GL_NO_ERROR();
390
391 GLuint result = GL_FALSE;
392 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
393 EXPECT_GL_NO_ERROR();
394
395 EXPECT_GL_TRUE(result);
396 }
397
398 // Test that switching framebuffers without actually drawing, then issuing a masked clear while a
399 // query is active works.
TEST_P(OcclusionQueriesTestES3,SwitchFramebuffersThenMaskedClear)400 TEST_P(OcclusionQueriesTestES3, SwitchFramebuffersThenMaskedClear)
401 {
402 constexpr GLint kSize = 10;
403
404 GLFramebuffer fbo1, fbo2;
405 GLRenderbuffer rbo1, rbo2;
406
407 // Set up two framebuffers
408 glBindRenderbuffer(GL_RENDERBUFFER, rbo1);
409 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, kSize, kSize);
410
411 glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
412 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo1);
413
414 glBindRenderbuffer(GL_RENDERBUFFER, rbo2);
415 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, kSize, kSize);
416
417 glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
418 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo2);
419
420 // Start render pass on fbo1
421 glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
422 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
423 drawQuad(program, essl1_shaders::PositionAttrib(), 0);
424
425 // Begin a query
426 GLQuery query;
427 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
428
429 // Switch to another render pass and clear. In the Vulkan backend, this clear is deferred, so
430 // while the framebuffer binding is synced, the previous render pass is not necessarily closed.
431 glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
432 glClear(GL_STENCIL_BUFFER_BIT);
433
434 // Switch back to the original render pass and issue a masked stencil clear. In the Vulkan
435 // backend, this is done with a draw call.
436 glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
437 glStencilMask(0xAA);
438 glClearStencil(0xF4);
439 glClear(GL_STENCIL_BUFFER_BIT);
440
441 // Verify the clear worked.
442 GLRenderbuffer color;
443 glBindRenderbuffer(GL_RENDERBUFFER, color);
444 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize);
445 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
446
447 glEnable(GL_STENCIL_TEST);
448 glStencilFunc(GL_ALWAYS, 0xA4, 0xFF);
449 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
450 glStencilMask(0xFF);
451
452 glClear(GL_COLOR_BUFFER_BIT);
453 drawQuad(program, essl1_shaders::PositionAttrib(), 0);
454
455 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
456 ASSERT_GL_NO_ERROR();
457 }
458
459 // Test multiple occlusion queries.
TEST_P(OcclusionQueriesTest,MultiQueries)460 TEST_P(OcclusionQueriesTest, MultiQueries)
461 {
462 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
463 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
464
465 // http://anglebug.com/4925
466 ANGLE_SKIP_TEST_IF(IsOpenGL() || IsD3D11());
467
468 // TODO(anglebug.com/5360): Failing on ARM-based Apple DTKs.
469 ANGLE_SKIP_TEST_IF(IsMac() && IsARM64() && IsDesktopOpenGL());
470
471 GLQueryEXT query[5];
472
473 // First query
474 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[0]);
475
476 EXPECT_GL_NO_ERROR();
477
478 glEnable(GL_DEPTH_TEST);
479 glDepthMask(GL_TRUE);
480 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
481
482 EXPECT_GL_NO_ERROR();
483
484 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
485
486 EXPECT_GL_NO_ERROR();
487
488 // Due to implementation might skip in-renderpass flush, we are using glFinish here to force a
489 // flush. A flush shound't clear the query result.
490 glFinish();
491
492 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
493 drawQuad(mProgram, essl1_shaders::PositionAttrib(), -2, 0.25f); // this quad should be occluded
494 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
495 // First query ends
496
497 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f,
498 0.25f); // this quad should not be occluded
499
500 // Second query
501 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[1]);
502 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
503 0.25f); // this quad should be occluded
504 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
505
506 // Third query
507 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[2]);
508 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
509 0.5f); // this quad should not be occluded
510 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
511 // ------------
512 glFinish();
513
514 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
515 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight());
516 glEnable(GL_SCISSOR_TEST);
517 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
518 0.5f); // this quad should not be occluded
519
520 // Fourth query: begin query then end then begin again
521 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[3]);
522 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
523 1); // this quad should not be occluded
524 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
525 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[3]);
526 EXPECT_GL_NO_ERROR();
527 // glClear should not be counted toward query);
528 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
529 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
530
531 // Fifth query spans across frames
532 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query[4]);
533 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f,
534 0.25f); // this quad should not be occluded
535
536 swapBuffers();
537
538 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
539
540 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.9f,
541 0.5f); // this quad should not be occluded
542 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
543
544 GLuint result = GL_TRUE;
545 glGetQueryObjectuivEXT(query[0], GL_QUERY_RESULT_EXT,
546 &result); // will block waiting for result
547 EXPECT_GL_NO_ERROR();
548 EXPECT_GL_TRUE(result);
549
550 glGetQueryObjectuivEXT(query[1], GL_QUERY_RESULT_EXT,
551 &result); // will block waiting for result
552 EXPECT_GL_NO_ERROR();
553 EXPECT_GL_FALSE(result);
554
555 glGetQueryObjectuivEXT(query[2], GL_QUERY_RESULT_EXT,
556 &result); // will block waiting for result
557 EXPECT_GL_NO_ERROR();
558 EXPECT_GL_TRUE(result);
559
560 glGetQueryObjectuivEXT(query[3], GL_QUERY_RESULT_EXT,
561 &result); // will block waiting for result
562 EXPECT_GL_NO_ERROR();
563 EXPECT_GL_FALSE(result);
564
565 glGetQueryObjectuivEXT(query[4], GL_QUERY_RESULT_EXT,
566 &result); // will block waiting for result
567 EXPECT_GL_NO_ERROR();
568 EXPECT_GL_TRUE(result);
569 }
570
TEST_P(OcclusionQueriesTest,Errors)571 TEST_P(OcclusionQueriesTest, Errors)
572 {
573 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
574 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
575
576 glDepthMask(GL_TRUE);
577 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
578
579 EXPECT_GL_NO_ERROR();
580
581 GLuint query = 0;
582 GLuint query2 = 0;
583 glGenQueriesEXT(1, &query);
584
585 EXPECT_GL_FALSE(glIsQueryEXT(query));
586 EXPECT_GL_FALSE(glIsQueryEXT(query2));
587
588 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0); // can't pass 0 as query id
589 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
590
591 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
592 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
593 query2); // can't initiate a query while one's already active
594 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
595
596 EXPECT_GL_TRUE(glIsQueryEXT(query));
597 EXPECT_GL_FALSE(glIsQueryEXT(query2)); // have not called begin
598
599 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.8f); // this quad should not be occluded
600 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // no active query for this target
601 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
602 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
603
604 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
605 query); // can't begin a query as a different type than previously used
606 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
607
608 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
609 query2); // have to call genqueries first
610 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
611
612 glGenQueriesEXT(1, &query2);
613 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, query2); // should be ok now
614 EXPECT_GL_TRUE(glIsQueryEXT(query2));
615
616 drawQuad(mProgram, essl1_shaders::PositionAttrib(),
617 0.3f); // this should draw in front of other quad
618 glDeleteQueriesEXT(1, &query2); // should delete when query becomes inactive
619 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); // should not incur error; should delete
620 // query + 1 at end of execution.
621 EXPECT_GL_NO_ERROR();
622
623 swapBuffers();
624
625 EXPECT_GL_NO_ERROR();
626
627 GLuint ready = GL_FALSE;
628 glGetQueryObjectuivEXT(query2, GL_QUERY_RESULT_AVAILABLE_EXT,
629 &ready); // this query is now deleted
630 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
631
632 EXPECT_GL_NO_ERROR();
633 }
634
635 // Test that running multiple simultaneous queries from multiple EGL contexts returns the correct
636 // result for each query. Helps expose bugs in ANGLE's virtual contexts.
TEST_P(OcclusionQueriesTest,MultiContext)637 TEST_P(OcclusionQueriesTest, MultiContext)
638 {
639 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
640 !IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"));
641
642 // TODO(cwallez@chromium.org): Suppression for http://anglebug.com/3080
643 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan());
644
645 // Test skipped because the D3D backends cannot support simultaneous queries on multiple
646 // contexts yet.
647 ANGLE_SKIP_TEST_IF(GetParam() == ES2_D3D9() || GetParam() == ES2_D3D11() ||
648 GetParam() == ES3_D3D11());
649
650 glDepthMask(GL_TRUE);
651 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
652
653 // draw a quad at depth 0.5
654 glEnable(GL_DEPTH_TEST);
655 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
656
657 EGLWindow *window = getEGLWindow();
658
659 EGLDisplay display = window->getDisplay();
660 EGLConfig config = window->getConfig();
661 EGLSurface surface = window->getSurface();
662
663 EGLint contextAttributes[] = {
664 EGL_CONTEXT_MAJOR_VERSION_KHR,
665 GetParam().majorVersion,
666 EGL_CONTEXT_MINOR_VERSION_KHR,
667 GetParam().minorVersion,
668 EGL_NONE,
669 };
670
671 const size_t passCount = 5;
672 struct ContextInfo
673 {
674 EGLContext context;
675 GLuint program;
676 GLuint query;
677 bool visiblePasses[passCount];
678 bool shouldPass;
679 };
680
681 ContextInfo contexts[] = {
682 {
683 EGL_NO_CONTEXT,
684 0,
685 0,
686 {false, false, false, false, false},
687 false,
688 },
689 {
690 EGL_NO_CONTEXT,
691 0,
692 0,
693 {false, true, false, true, false},
694 true,
695 },
696 {
697 EGL_NO_CONTEXT,
698 0,
699 0,
700 {false, false, false, false, false},
701 false,
702 },
703 {
704 EGL_NO_CONTEXT,
705 0,
706 0,
707 {true, true, false, true, true},
708 true,
709 },
710 {
711 EGL_NO_CONTEXT,
712 0,
713 0,
714 {false, true, true, true, true},
715 true,
716 },
717 {
718 EGL_NO_CONTEXT,
719 0,
720 0,
721 {true, false, false, true, false},
722 true,
723 },
724 {
725 EGL_NO_CONTEXT,
726 0,
727 0,
728 {false, false, false, false, false},
729 false,
730 },
731 {
732 EGL_NO_CONTEXT,
733 0,
734 0,
735 {false, false, false, false, false},
736 false,
737 },
738 };
739
740 for (auto &context : contexts)
741 {
742 context.context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
743 ASSERT_NE(context.context, EGL_NO_CONTEXT);
744
745 eglMakeCurrent(display, surface, surface, context.context);
746
747 context.program = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
748 ASSERT_NE(context.program, 0u);
749
750 glDepthMask(GL_FALSE);
751 glEnable(GL_DEPTH_TEST);
752
753 glGenQueriesEXT(1, &context.query);
754 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, context.query);
755
756 ASSERT_GL_NO_ERROR();
757 }
758
759 for (size_t pass = 0; pass < passCount; pass++)
760 {
761 for (const auto &context : contexts)
762 {
763 eglMakeCurrent(display, surface, surface, context.context);
764
765 float depth = context.visiblePasses[pass] ? mRNG.randomFloatBetween(0.0f, 0.4f)
766 : mRNG.randomFloatBetween(0.6f, 1.0f);
767 drawQuad(context.program, essl1_shaders::PositionAttrib(), depth);
768
769 EXPECT_GL_NO_ERROR();
770 }
771 }
772
773 for (const auto &context : contexts)
774 {
775 eglMakeCurrent(display, surface, surface, context.context);
776 glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
777
778 GLuint result = GL_TRUE;
779 glGetQueryObjectuivEXT(context.query, GL_QUERY_RESULT_EXT, &result);
780
781 EXPECT_GL_NO_ERROR();
782
783 GLuint expectation = context.shouldPass ? GL_TRUE : GL_FALSE;
784 EXPECT_EQ(expectation, result);
785 }
786
787 eglMakeCurrent(display, surface, surface, window->getContext());
788
789 for (auto &context : contexts)
790 {
791 eglDestroyContext(display, context.context);
792 context.context = EGL_NO_CONTEXT;
793 }
794 }
795
796 class OcclusionQueriesNoSurfaceTestES3 : public ANGLETestBase,
797 public ::testing::TestWithParam<angle::PlatformParameters>
798 {
799 protected:
OcclusionQueriesNoSurfaceTestES3()800 OcclusionQueriesNoSurfaceTestES3()
801 : ANGLETestBase(GetParam()), mUnusedConfig(0), mUnusedDisplay(nullptr)
802 {
803 setWindowWidth(kWidth);
804 setWindowHeight(kHeight);
805 setConfigRedBits(8);
806 setConfigGreenBits(8);
807 setConfigBlueBits(8);
808 setConfigAlphaBits(8);
809 setDeferContextInit(true);
810 }
811
812 static constexpr int kWidth = 300;
813 static constexpr int kHeight = 300;
814
SetUp()815 void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
TearDown()816 void TearDown() override { ANGLETestBase::ANGLETestTearDown(); }
817
swapBuffers()818 void swapBuffers() override {}
819
820 EGLConfig mUnusedConfig;
821 EGLDisplay mUnusedDisplay;
822 };
823
824 // This test provked a bug in the Metal backend that only happened
825 // when there was no surfaces on the EGLContext and a query had
826 // just ended after a draw and then switching to a different
827 // context.
TEST_P(OcclusionQueriesNoSurfaceTestES3,SwitchingContextsWithQuery)828 TEST_P(OcclusionQueriesNoSurfaceTestES3, SwitchingContextsWithQuery)
829 {
830 EGLWindow *window = getEGLWindow();
831
832 EGLDisplay display = window->getDisplay();
833 EGLConfig config = window->getConfig();
834
835 EGLint contextAttributes[] = {
836 EGL_CONTEXT_MAJOR_VERSION_KHR,
837 GetParam().majorVersion,
838 EGL_CONTEXT_MINOR_VERSION_KHR,
839 GetParam().minorVersion,
840 EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE,
841 EGL_TRUE,
842 EGL_NONE,
843 };
844
845 // The following GL objects are implicitly deleted in
846 // ContextInfo's destructor before the EGLContext is manually destroyed
847 struct ContextInfo
848 {
849 EGLContext context;
850 GLBuffer buf;
851 GLProgram program;
852 GLFramebuffer fb;
853 GLTexture tex;
854 GLQuery query;
855 };
856
857 // ContextInfo contains objects that clean themselves on destruction.
858 // We want these objects to stick around until the test ends.
859 std::vector<ContextInfo *> pairs;
860
861 for (size_t i = 0; i < 2; ++i)
862 {
863 ContextInfo *infos[] = {
864 new ContextInfo(),
865 new ContextInfo(),
866 };
867
868 for (ContextInfo *pinfo : infos)
869 {
870 pairs.push_back(pinfo);
871 ContextInfo &info = *pinfo;
872
873 info.context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
874 ASSERT_NE(info.context, EGL_NO_CONTEXT);
875
876 // Make context current context with no draw and read surface.
877 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info.context));
878
879 // Create something to draw to.
880 glBindFramebuffer(GL_FRAMEBUFFER, info.fb);
881 glBindTexture(GL_TEXTURE_2D, info.tex);
882 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
883 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, info.tex,
884 0);
885 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
886
887 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
888 EXPECT_GL_NO_ERROR();
889 glFlush();
890 }
891
892 // Setup an shader and quad buffer
893 for (ContextInfo *pinfo : infos)
894 {
895 ContextInfo &info = *pinfo;
896 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info.context));
897
898 constexpr char kVS[] = R"(
899 attribute vec4 position;
900 void main() {
901 gl_Position = position;
902 }
903 )";
904
905 constexpr char kFS[] = R"(
906 precision mediump float;
907 void main() {
908 gl_FragColor = vec4(1, 0, 0, 1);
909 }
910 )";
911
912 info.program.makeRaster(kVS, kFS);
913 glUseProgram(info.program);
914
915 constexpr float vertices[] = {
916 -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
917 };
918 glBindBuffer(GL_ARRAY_BUFFER, info.buf);
919 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
920 glEnableVertexAttribArray(0);
921 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
922 EXPECT_GL_NO_ERROR();
923 }
924
925 ContextInfo &info1 = *infos[0];
926 ContextInfo &info2 = *infos[1];
927
928 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info1.context));
929
930 glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, info1.query);
931 glFlush();
932
933 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info2.context));
934 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
935 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info1.context));
936
937 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
938
939 glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
940 EXPECT_GL_NO_ERROR();
941
942 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info2.context));
943 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
944 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info1.context));
945 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info2.context));
946 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, info1.context));
947 }
948
949 // destroy GL objects on the correct context.
950 for (ContextInfo *pinfo : pairs)
951 {
952 EGLContext context = pinfo->context;
953 ASSERT_EGL_TRUE(eglMakeCurrent(display, nullptr, nullptr, context));
954 EXPECT_GL_NO_ERROR();
955 delete pinfo;
956 ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
957 ASSERT_EGL_TRUE(eglDestroyContext(display, context));
958 EXPECT_EGL_SUCCESS();
959 }
960 }
961
962 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(OcclusionQueriesTest);
963
964 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OcclusionQueriesTestES3);
965 ANGLE_INSTANTIATE_TEST_ES3_AND(
966 OcclusionQueriesTestES3,
967 ES3_VULKAN().enable(Feature::PreferSubmitOnAnySamplesPassedQueryEnd));
968
969 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OcclusionQueriesNoSurfaceTestES3);
970 ANGLE_INSTANTIATE_TEST_ES3(OcclusionQueriesNoSurfaceTestES3);
971