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