• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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