xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/QueryGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // QueryGL.cpp: Implements the class methods for QueryGL.
8 
9 #include "libANGLE/renderer/gl/QueryGL.h"
10 
11 #include "common/debug.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/renderer/gl/ContextGL.h"
14 #include "libANGLE/renderer/gl/FunctionsGL.h"
15 #include "libANGLE/renderer/gl/StateManagerGL.h"
16 #include "libANGLE/renderer/gl/renderergl_utils.h"
17 
18 namespace
19 {
20 
MergeQueryResults(gl::QueryType type,GLuint64 currentResult,GLuint64 newResult)21 GLuint64 MergeQueryResults(gl::QueryType type, GLuint64 currentResult, GLuint64 newResult)
22 {
23     switch (type)
24     {
25         case gl::QueryType::AnySamples:
26         case gl::QueryType::AnySamplesConservative:
27             return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
28 
29         case gl::QueryType::TransformFeedbackPrimitivesWritten:
30             return currentResult + newResult;
31 
32         case gl::QueryType::TimeElapsed:
33             return currentResult + newResult;
34 
35         case gl::QueryType::Timestamp:
36             return newResult;
37 
38         case gl::QueryType::PrimitivesGenerated:
39             return currentResult + newResult;
40 
41         default:
42             UNREACHABLE();
43             return 0;
44     }
45 }
46 
47 // Some drivers tend to hang when flushing pending queries.  Wait until this number of queries have
48 // added up before checking if results are ready.
49 constexpr uint32_t kPauseResumeFlushThreshold = 5;
50 }  // anonymous namespace
51 
52 namespace rx
53 {
54 
QueryGL(gl::QueryType type)55 QueryGL::QueryGL(gl::QueryType type) : QueryImpl(type) {}
56 
~QueryGL()57 QueryGL::~QueryGL() {}
58 
StandardQueryGL(gl::QueryType type,const FunctionsGL * functions,StateManagerGL * stateManager)59 StandardQueryGL::StandardQueryGL(gl::QueryType type,
60                                  const FunctionsGL *functions,
61                                  StateManagerGL *stateManager)
62     : QueryGL(type),
63       mFunctions(functions),
64       mStateManager(stateManager),
65       mActiveQuery(0),
66       mPendingQueries(),
67       mResultSum(0)
68 {}
69 
~StandardQueryGL()70 StandardQueryGL::~StandardQueryGL()
71 {
72     clearInternalQueries();
73 }
74 
clearInternalQueries()75 void StandardQueryGL::clearInternalQueries()
76 {
77     if (mActiveQuery != 0)
78     {
79         mStateManager->endQuery(mType, this, mActiveQuery);
80         mFunctions->deleteQueries(1, &mActiveQuery);
81         mActiveQuery = 0;
82     }
83 
84     while (!mPendingQueries.empty())
85     {
86         GLuint id = mPendingQueries.front();
87         mFunctions->deleteQueries(1, &id);
88         mPendingQueries.pop_front();
89     }
90 }
91 
begin(const gl::Context * context)92 angle::Result StandardQueryGL::begin(const gl::Context *context)
93 {
94     clearInternalQueries();
95     mResultSum = 0;
96     return resume(context);
97 }
98 
end(const gl::Context * context)99 angle::Result StandardQueryGL::end(const gl::Context *context)
100 {
101     return pause(context);
102 }
103 
queryCounter(const gl::Context * context)104 angle::Result StandardQueryGL::queryCounter(const gl::Context *context)
105 {
106     ASSERT(mType == gl::QueryType::Timestamp);
107 
108     // Directly create a query for the timestamp and add it to the pending query queue, as timestamp
109     // queries do not have the traditional begin/end block and never need to be paused/resumed
110     GLuint query;
111     mFunctions->genQueries(1, &query);
112     mFunctions->queryCounter(query, GL_TIMESTAMP);
113     mPendingQueries.push_back(query);
114 
115     return angle::Result::Continue;
116 }
117 
118 template <typename T>
getResultBase(const gl::Context * context,T * params)119 angle::Result StandardQueryGL::getResultBase(const gl::Context *context, T *params)
120 {
121     ASSERT(mActiveQuery == 0);
122 
123     ANGLE_TRY(flush(context, true));
124     ASSERT(mPendingQueries.empty());
125     *params = static_cast<T>(mResultSum);
126 
127     return angle::Result::Continue;
128 }
129 
getResult(const gl::Context * context,GLint * params)130 angle::Result StandardQueryGL::getResult(const gl::Context *context, GLint *params)
131 {
132     return getResultBase(context, params);
133 }
134 
getResult(const gl::Context * context,GLuint * params)135 angle::Result StandardQueryGL::getResult(const gl::Context *context, GLuint *params)
136 {
137     return getResultBase(context, params);
138 }
139 
getResult(const gl::Context * context,GLint64 * params)140 angle::Result StandardQueryGL::getResult(const gl::Context *context, GLint64 *params)
141 {
142     return getResultBase(context, params);
143 }
144 
getResult(const gl::Context * context,GLuint64 * params)145 angle::Result StandardQueryGL::getResult(const gl::Context *context, GLuint64 *params)
146 {
147     return getResultBase(context, params);
148 }
149 
isResultAvailable(const gl::Context * context,bool * available)150 angle::Result StandardQueryGL::isResultAvailable(const gl::Context *context, bool *available)
151 {
152     ASSERT(mActiveQuery == 0);
153 
154     ANGLE_TRY(flush(context, false));
155     *available = mPendingQueries.empty();
156     return angle::Result::Continue;
157 }
158 
pause(const gl::Context * context)159 angle::Result StandardQueryGL::pause(const gl::Context *context)
160 {
161     if (mActiveQuery != 0)
162     {
163         mStateManager->endQuery(mType, this, mActiveQuery);
164 
165         mPendingQueries.push_back(mActiveQuery);
166         mActiveQuery = 0;
167     }
168 
169     // Flush to make sure the pending queries don't add up too much.
170     if (mPendingQueries.size() >= kPauseResumeFlushThreshold)
171     {
172         ANGLE_TRY(flush(context, false));
173     }
174 
175     return angle::Result::Continue;
176 }
177 
resume(const gl::Context * context)178 angle::Result StandardQueryGL::resume(const gl::Context *context)
179 {
180     if (mActiveQuery == 0)
181     {
182         // Flush to make sure the pending queries don't add up too much.
183         if (mPendingQueries.size() >= kPauseResumeFlushThreshold)
184         {
185             ANGLE_TRY(flush(context, false));
186         }
187 
188         mFunctions->genQueries(1, &mActiveQuery);
189         mStateManager->beginQuery(mType, this, mActiveQuery);
190 
191         ContextGL *contextGL = GetImplAs<ContextGL>(context);
192         contextGL->markWorkSubmitted();
193     }
194 
195     return angle::Result::Continue;
196 }
197 
flush(const gl::Context * context,bool force)198 angle::Result StandardQueryGL::flush(const gl::Context *context, bool force)
199 {
200     while (!mPendingQueries.empty())
201     {
202         GLuint id = mPendingQueries.front();
203         if (!force)
204         {
205             GLuint resultAvailable = 0;
206             mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
207             if (resultAvailable == GL_FALSE)
208             {
209                 return angle::Result::Continue;
210             }
211         }
212 
213         // Even though getQueryObjectui64v was introduced for timer queries, there is nothing in the
214         // standard that says that it doesn't work for any other queries. It also passes on all the
215         // trybots, so we use it if it is available
216         if (mFunctions->getQueryObjectui64v != nullptr)
217         {
218             GLuint64 result = 0;
219             mFunctions->getQueryObjectui64v(id, GL_QUERY_RESULT, &result);
220             mResultSum = MergeQueryResults(mType, mResultSum, result);
221         }
222         else
223         {
224             GLuint result = 0;
225             mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
226             mResultSum = MergeQueryResults(mType, mResultSum, static_cast<GLuint64>(result));
227         }
228 
229         mFunctions->deleteQueries(1, &id);
230 
231         mPendingQueries.pop_front();
232     }
233 
234     return angle::Result::Continue;
235 }
236 
237 class SyncProviderGL
238 {
239   public:
~SyncProviderGL()240     virtual ~SyncProviderGL() {}
init(const gl::Context * context,gl::QueryType queryType)241     virtual angle::Result init(const gl::Context *context, gl::QueryType queryType)
242     {
243         return angle::Result::Continue;
244     }
245     virtual angle::Result flush(const gl::Context *context, bool force, bool *finished) = 0;
246 };
247 
248 class SyncProviderGLSync : public SyncProviderGL
249 {
250   public:
SyncProviderGLSync(const FunctionsGL * functions)251     SyncProviderGLSync(const FunctionsGL *functions) : mFunctions(functions), mSync(nullptr) {}
252 
~SyncProviderGLSync()253     ~SyncProviderGLSync() override { mFunctions->deleteSync(mSync); }
254 
init(const gl::Context * context,gl::QueryType type)255     angle::Result init(const gl::Context *context, gl::QueryType type) override
256     {
257         ContextGL *contextGL = GetImplAs<ContextGL>(context);
258         mSync                = mFunctions->fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
259         ANGLE_CHECK(contextGL, mSync != 0, "glFenceSync failed to create a GLsync object.",
260                     GL_OUT_OF_MEMORY);
261         contextGL->markWorkSubmitted();
262         return angle::Result::Continue;
263     }
264 
flush(const gl::Context * context,bool force,bool * finished)265     angle::Result flush(const gl::Context *context, bool force, bool *finished) override
266     {
267         if (force)
268         {
269             mFunctions->clientWaitSync(mSync, 0, 0);
270             *finished = true;
271         }
272         else
273         {
274             GLint value = 0;
275             mFunctions->getSynciv(mSync, GL_SYNC_STATUS, 1, nullptr, &value);
276             *finished = (value == GL_SIGNALED);
277         }
278 
279         return angle::Result::Continue;
280     }
281 
282   private:
283     const FunctionsGL *mFunctions;
284     GLsync mSync;
285 };
286 
287 class SyncProviderGLQuery : public SyncProviderGL
288 {
289   public:
SyncProviderGLQuery(const FunctionsGL * functions)290     SyncProviderGLQuery(const FunctionsGL *functions) : mFunctions(functions), mQuery(0) {}
291 
init(const gl::Context * context,gl::QueryType type)292     angle::Result init(const gl::Context *context, gl::QueryType type) override
293     {
294         StateManagerGL *stateManager = GetStateManagerGL(context);
295 
296         mFunctions->genQueries(1, &mQuery);
297         ANGLE_TRY(stateManager->pauseQuery(context, type));
298         mFunctions->beginQuery(ToGLenum(type), mQuery);
299         mFunctions->endQuery(ToGLenum(type));
300         return stateManager->resumeQuery(context, type);
301     }
302 
~SyncProviderGLQuery()303     ~SyncProviderGLQuery() override { mFunctions->deleteQueries(1, &mQuery); }
304 
flush(const gl::Context * context,bool force,bool * finished)305     angle::Result flush(const gl::Context *context, bool force, bool *finished) override
306     {
307         if (force)
308         {
309             GLint result = 0;
310             mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT, &result);
311             *finished = true;
312         }
313         else
314         {
315             GLint available = 0;
316             mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &available);
317             *finished = (available == GL_TRUE);
318         }
319 
320         return angle::Result::Continue;
321     }
322 
323   private:
324     const FunctionsGL *mFunctions;
325     GLuint mQuery;
326 };
327 
SyncQueryGL(gl::QueryType type,const FunctionsGL * functions)328 SyncQueryGL::SyncQueryGL(gl::QueryType type, const FunctionsGL *functions)
329     : QueryGL(type), mFunctions(functions), mSyncProvider(nullptr), mFinished(false)
330 {
331     ASSERT(IsSupported(mFunctions));
332     ASSERT(type == gl::QueryType::CommandsCompleted);
333 }
334 
~SyncQueryGL()335 SyncQueryGL::~SyncQueryGL() {}
336 
IsSupported(const FunctionsGL * functions)337 bool SyncQueryGL::IsSupported(const FunctionsGL *functions)
338 {
339     return nativegl::SupportsFenceSync(functions) || nativegl::SupportsOcclusionQueries(functions);
340 }
341 
begin(const gl::Context * context)342 angle::Result SyncQueryGL::begin(const gl::Context *context)
343 {
344     return angle::Result::Continue;
345 }
346 
end(const gl::Context * context)347 angle::Result SyncQueryGL::end(const gl::Context *context)
348 {
349     if (nativegl::SupportsFenceSync(mFunctions))
350     {
351         mSyncProvider.reset(new SyncProviderGLSync(mFunctions));
352     }
353     else if (nativegl::SupportsOcclusionQueries(mFunctions))
354     {
355         mSyncProvider.reset(new SyncProviderGLQuery(mFunctions));
356     }
357     else
358     {
359         ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
360     }
361     ANGLE_TRY(mSyncProvider->init(context, gl::QueryType::AnySamples));
362     return angle::Result::Continue;
363 }
364 
queryCounter(const gl::Context * context)365 angle::Result SyncQueryGL::queryCounter(const gl::Context *context)
366 {
367     UNREACHABLE();
368     return angle::Result::Continue;
369 }
370 
getResult(const gl::Context * context,GLint * params)371 angle::Result SyncQueryGL::getResult(const gl::Context *context, GLint *params)
372 {
373     return getResultBase(context, params);
374 }
375 
getResult(const gl::Context * context,GLuint * params)376 angle::Result SyncQueryGL::getResult(const gl::Context *context, GLuint *params)
377 {
378     return getResultBase(context, params);
379 }
380 
getResult(const gl::Context * context,GLint64 * params)381 angle::Result SyncQueryGL::getResult(const gl::Context *context, GLint64 *params)
382 {
383     return getResultBase(context, params);
384 }
385 
getResult(const gl::Context * context,GLuint64 * params)386 angle::Result SyncQueryGL::getResult(const gl::Context *context, GLuint64 *params)
387 {
388     return getResultBase(context, params);
389 }
390 
isResultAvailable(const gl::Context * context,bool * available)391 angle::Result SyncQueryGL::isResultAvailable(const gl::Context *context, bool *available)
392 {
393     ANGLE_TRY(flush(context, false));
394     *available = mFinished;
395     return angle::Result::Continue;
396 }
397 
pause(const gl::Context * context)398 angle::Result SyncQueryGL::pause(const gl::Context *context)
399 {
400     return angle::Result::Continue;
401 }
402 
resume(const gl::Context * context)403 angle::Result SyncQueryGL::resume(const gl::Context *context)
404 {
405     return angle::Result::Continue;
406 }
407 
flush(const gl::Context * context,bool force)408 angle::Result SyncQueryGL::flush(const gl::Context *context, bool force)
409 {
410     if (mSyncProvider == nullptr)
411     {
412         ASSERT(mFinished);
413         return angle::Result::Continue;
414     }
415 
416     ANGLE_TRY(mSyncProvider->flush(context, force, &mFinished));
417     if (mFinished)
418     {
419         mSyncProvider.reset();
420     }
421 
422     return angle::Result::Continue;
423 }
424 
425 template <typename T>
getResultBase(const gl::Context * context,T * params)426 angle::Result SyncQueryGL::getResultBase(const gl::Context *context, T *params)
427 {
428     ANGLE_TRY(flush(context, true));
429     *params = static_cast<T>(mFinished ? GL_TRUE : GL_FALSE);
430     return angle::Result::Continue;
431 }
432 }  // namespace rx
433