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