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