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