blob: 9ed36be56c18e38c9da893830b56301615cddd2e [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
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"
Geoff Langf0aa8422015-09-29 15:08:34 -040012#include "libANGLE/renderer/gl/FunctionsGL.h"
13#include "libANGLE/renderer/gl/StateManagerGL.h"
Geoff Langa20fc002016-08-08 15:19:56 -040014#include "libANGLE/renderer/gl/renderergl_utils.h"
Geoff Langf0aa8422015-09-29 15:08:34 -040015
16namespace
17{
18
Ian Ewell3ffd78b2016-01-22 16:09:42 -050019GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult)
Geoff Langf0aa8422015-09-29 15:08:34 -040020{
21 switch (type)
22 {
23 case GL_ANY_SAMPLES_PASSED:
24 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
25 return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
26
27 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
28 return currentResult + newResult;
29
Ian Ewell3ffd78b2016-01-22 16:09:42 -050030 case GL_TIME_ELAPSED:
31 return currentResult + newResult;
32
33 case GL_TIMESTAMP:
34 return newResult;
35
Geoff Langf0aa8422015-09-29 15:08:34 -040036 default:
37 UNREACHABLE();
38 return 0;
39 }
40}
41
42} // anonymous namespace
Geoff Langf9a6f082015-01-22 13:32:49 -050043
44namespace rx
45{
46
Geoff Langa20fc002016-08-08 15:19:56 -040047QueryGL::QueryGL(GLenum type) : QueryImpl(type)
48{
49}
50
51QueryGL::~QueryGL()
52{
53}
54
55StandardQueryGL::StandardQueryGL(GLenum type,
56 const FunctionsGL *functions,
57 StateManagerGL *stateManager)
58 : QueryGL(type),
Geoff Langf0aa8422015-09-29 15:08:34 -040059 mType(type),
60 mFunctions(functions),
61 mStateManager(stateManager),
62 mActiveQuery(0),
63 mPendingQueries(),
64 mResultSum(0)
65{
66}
Geoff Langf9a6f082015-01-22 13:32:49 -050067
Geoff Langa20fc002016-08-08 15:19:56 -040068StandardQueryGL::~StandardQueryGL()
Geoff Langf0aa8422015-09-29 15:08:34 -040069{
70 mStateManager->deleteQuery(mActiveQuery);
71 mStateManager->onDeleteQueryObject(this);
72 while (!mPendingQueries.empty())
73 {
74 mStateManager->deleteQuery(mPendingQueries.front());
75 mPendingQueries.pop_front();
76 }
77}
Geoff Langf9a6f082015-01-22 13:32:49 -050078
Geoff Langa20fc002016-08-08 15:19:56 -040079gl::Error StandardQueryGL::begin()
Geoff Langf9a6f082015-01-22 13:32:49 -050080{
Geoff Langf0aa8422015-09-29 15:08:34 -040081 mResultSum = 0;
Ian Ewell292f0052016-02-04 10:37:32 -050082 mStateManager->onBeginQuery(this);
83 return resume();
Geoff Langf9a6f082015-01-22 13:32:49 -050084}
85
Geoff Langa20fc002016-08-08 15:19:56 -040086gl::Error StandardQueryGL::end()
Geoff Langf9a6f082015-01-22 13:32:49 -050087{
Geoff Langf0aa8422015-09-29 15:08:34 -040088 return pause();
Geoff Langf9a6f082015-01-22 13:32:49 -050089}
90
Geoff Langa20fc002016-08-08 15:19:56 -040091gl::Error StandardQueryGL::queryCounter()
Ian Ewell3ffd78b2016-01-22 16:09:42 -050092{
93 ASSERT(mType == GL_TIMESTAMP);
94
95 // Directly create a query for the timestamp and add it to the pending query queue, as timestamp
96 // queries do not have the traditional begin/end block and never need to be paused/resumed
97 GLuint query;
98 mFunctions->genQueries(1, &query);
99 mFunctions->queryCounter(query, GL_TIMESTAMP);
100 mPendingQueries.push_back(query);
101
He Yunchaoacd18982017-01-04 10:46:42 +0800102 return gl::NoError();
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500103}
104
105template <typename T>
Geoff Langa20fc002016-08-08 15:19:56 -0400106gl::Error StandardQueryGL::getResultBase(T *params)
Geoff Langf9a6f082015-01-22 13:32:49 -0500107{
Geoff Langf0aa8422015-09-29 15:08:34 -0400108 ASSERT(mActiveQuery == 0);
109
110 gl::Error error = flush(true);
111 if (error.isError())
112 {
113 return error;
114 }
115
116 ASSERT(mPendingQueries.empty());
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500117 *params = static_cast<T>(mResultSum);
Geoff Langf0aa8422015-09-29 15:08:34 -0400118
He Yunchaoacd18982017-01-04 10:46:42 +0800119 return gl::NoError();
Geoff Langf9a6f082015-01-22 13:32:49 -0500120}
121
Geoff Langa20fc002016-08-08 15:19:56 -0400122gl::Error StandardQueryGL::getResult(GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500123{
124 return getResultBase(params);
125}
126
Geoff Langa20fc002016-08-08 15:19:56 -0400127gl::Error StandardQueryGL::getResult(GLuint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500128{
129 return getResultBase(params);
130}
131
Geoff Langa20fc002016-08-08 15:19:56 -0400132gl::Error StandardQueryGL::getResult(GLint64 *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500133{
134 return getResultBase(params);
135}
136
Geoff Langa20fc002016-08-08 15:19:56 -0400137gl::Error StandardQueryGL::getResult(GLuint64 *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500138{
139 return getResultBase(params);
140}
141
Geoff Langa20fc002016-08-08 15:19:56 -0400142gl::Error StandardQueryGL::isResultAvailable(bool *available)
Geoff Langf9a6f082015-01-22 13:32:49 -0500143{
Geoff Langf0aa8422015-09-29 15:08:34 -0400144 ASSERT(mActiveQuery == 0);
145
146 gl::Error error = flush(false);
147 if (error.isError())
148 {
149 return error;
150 }
151
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500152 *available = mPendingQueries.empty();
He Yunchaoacd18982017-01-04 10:46:42 +0800153 return gl::NoError();
Geoff Langf0aa8422015-09-29 15:08:34 -0400154}
155
Geoff Langa20fc002016-08-08 15:19:56 -0400156gl::Error StandardQueryGL::pause()
Geoff Langf0aa8422015-09-29 15:08:34 -0400157{
158 if (mActiveQuery != 0)
159 {
160 mStateManager->endQuery(mType, mActiveQuery);
161
162 mPendingQueries.push_back(mActiveQuery);
163 mActiveQuery = 0;
164 }
165
166 // Flush to make sure the pending queries don't add up too much.
167 gl::Error error = flush(false);
168 if (error.isError())
169 {
170 return error;
171 }
172
He Yunchaoacd18982017-01-04 10:46:42 +0800173 return gl::NoError();
Geoff Langf0aa8422015-09-29 15:08:34 -0400174}
175
Geoff Langa20fc002016-08-08 15:19:56 -0400176gl::Error StandardQueryGL::resume()
Geoff Langf0aa8422015-09-29 15:08:34 -0400177{
178 if (mActiveQuery == 0)
179 {
180 // Flush to make sure the pending queries don't add up too much.
181 gl::Error error = flush(false);
182 if (error.isError())
183 {
184 return error;
185 }
186
187 mFunctions->genQueries(1, &mActiveQuery);
188 mStateManager->beginQuery(mType, mActiveQuery);
189 }
190
He Yunchaoacd18982017-01-04 10:46:42 +0800191 return gl::NoError();
Geoff Langf0aa8422015-09-29 15:08:34 -0400192}
193
Geoff Langa20fc002016-08-08 15:19:56 -0400194gl::Error StandardQueryGL::flush(bool force)
Geoff Langf0aa8422015-09-29 15:08:34 -0400195{
196 while (!mPendingQueries.empty())
197 {
198 GLuint id = mPendingQueries.front();
199 if (!force)
200 {
201 GLuint resultAvailable = 0;
202 mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
203 if (resultAvailable == GL_FALSE)
204 {
He Yunchaoacd18982017-01-04 10:46:42 +0800205 return gl::NoError();
Geoff Langf0aa8422015-09-29 15:08:34 -0400206 }
207 }
208
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500209 // Even though getQueryObjectui64v was introduced for timer queries, there is nothing in the
210 // standard that says that it doesn't work for any other queries. It also passes on all the
211 // trybots, so we use it if it is available
212 if (mFunctions->getQueryObjectui64v != nullptr)
213 {
214 GLuint64 result = 0;
215 mFunctions->getQueryObjectui64v(id, GL_QUERY_RESULT, &result);
216 mResultSum = MergeQueryResults(mType, mResultSum, result);
217 }
218 else
219 {
220 GLuint result = 0;
221 mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
222 mResultSum = MergeQueryResults(mType, mResultSum, static_cast<GLuint64>(result));
223 }
Geoff Langf0aa8422015-09-29 15:08:34 -0400224
225 mStateManager->deleteQuery(id);
226
227 mPendingQueries.pop_front();
228 }
229
He Yunchaoacd18982017-01-04 10:46:42 +0800230 return gl::NoError();
Geoff Langf9a6f082015-01-22 13:32:49 -0500231}
232
Geoff Langa20fc002016-08-08 15:19:56 -0400233class SyncProviderGL
234{
235 public:
236 virtual ~SyncProviderGL() {}
237 virtual gl::Error flush(bool force, bool *finished) = 0;
238};
239
240class SyncProviderGLSync : public SyncProviderGL
241{
242 public:
243 SyncProviderGLSync(const FunctionsGL *functions) : mFunctions(functions), mSync(nullptr)
244 {
245 mSync = mFunctions->fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
246 }
247
248 virtual ~SyncProviderGLSync() { mFunctions->deleteSync(mSync); }
249
250 gl::Error flush(bool force, bool *finished) override
251 {
252 if (force)
253 {
254 mFunctions->clientWaitSync(mSync, 0, 0);
255 *finished = true;
256 }
257 else
258 {
259 GLint value = 0;
260 mFunctions->getSynciv(mSync, GL_SYNC_STATUS, 1, nullptr, &value);
261 *finished = (value == GL_SIGNALED);
262 }
263
264 return gl::NoError();
265 }
266
267 private:
268 const FunctionsGL *mFunctions;
269 GLsync mSync;
270};
271
272class SyncProviderGLQuery : public SyncProviderGL
273{
274 public:
275 SyncProviderGLQuery(const FunctionsGL *functions,
276 StateManagerGL *stateManager,
277 GLenum queryType)
278 : mFunctions(functions), mQuery(0)
279 {
280 mFunctions->genQueries(1, &mQuery);
281 stateManager->pauseQuery(queryType);
282 mFunctions->beginQuery(queryType, mQuery);
283 mFunctions->endQuery(queryType);
284 stateManager->resumeQuery(queryType);
285 }
286
287 virtual ~SyncProviderGLQuery() { mFunctions->deleteQueries(1, &mQuery); }
288
289 gl::Error flush(bool force, bool *finished) override
290 {
291 if (force)
292 {
293 GLint result = 0;
294 mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT, &result);
295 *finished = true;
296 }
297 else
298 {
299 GLint available = 0;
300 mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &available);
301 *finished = (available == GL_TRUE);
302 }
303
304 return gl::NoError();
305 }
306
307 private:
308 const FunctionsGL *mFunctions;
309 GLuint mQuery;
310};
311
312SyncQueryGL::SyncQueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager)
313 : QueryGL(type),
314 mFunctions(functions),
315 mStateManager(stateManager),
316 mSyncProvider(nullptr),
317 mFinished(false)
318{
319 ASSERT(IsSupported(mFunctions));
320 ASSERT(type == GL_COMMANDS_COMPLETED_CHROMIUM);
321}
322
323SyncQueryGL::~SyncQueryGL()
324{
325}
326
327bool SyncQueryGL::IsSupported(const FunctionsGL *functions)
328{
329 return nativegl::SupportsFenceSync(functions) || nativegl::SupportsOcclusionQueries(functions);
330}
331
332gl::Error SyncQueryGL::begin()
333{
334 return gl::NoError();
335}
336
337gl::Error SyncQueryGL::end()
338{
339 if (nativegl::SupportsFenceSync(mFunctions))
340 {
341 mSyncProvider.reset(new SyncProviderGLSync(mFunctions));
342 }
343 else if (nativegl::SupportsOcclusionQueries(mFunctions))
344 {
345 mSyncProvider.reset(
346 new SyncProviderGLQuery(mFunctions, mStateManager, GL_ANY_SAMPLES_PASSED));
347 }
348 else
349 {
350 ASSERT(false);
351 return gl::Error(GL_INVALID_OPERATION, "No native support for sync queries.");
352 }
353 return gl::NoError();
354}
355
356gl::Error SyncQueryGL::queryCounter()
357{
358 UNREACHABLE();
359 return gl::NoError();
360}
361
362gl::Error SyncQueryGL::getResult(GLint *params)
363{
364 return getResultBase(params);
365}
366
367gl::Error SyncQueryGL::getResult(GLuint *params)
368{
369 return getResultBase(params);
370}
371
372gl::Error SyncQueryGL::getResult(GLint64 *params)
373{
374 return getResultBase(params);
375}
376
377gl::Error SyncQueryGL::getResult(GLuint64 *params)
378{
379 return getResultBase(params);
380}
381
382gl::Error SyncQueryGL::isResultAvailable(bool *available)
383{
384 ANGLE_TRY(flush(false));
385 *available = mFinished;
386 return gl::NoError();
387}
388
389gl::Error SyncQueryGL::pause()
390{
391 return gl::NoError();
392}
393
394gl::Error SyncQueryGL::resume()
395{
396 return gl::NoError();
397}
398
399gl::Error SyncQueryGL::flush(bool force)
400{
401 if (mSyncProvider == nullptr)
402 {
403 ASSERT(mFinished);
404 return gl::NoError();
405 }
406
407 ANGLE_TRY(mSyncProvider->flush(force, &mFinished));
408 if (mFinished)
409 {
410 mSyncProvider.reset();
411 }
412
413 return gl::NoError();
414}
415
416template <typename T>
417gl::Error SyncQueryGL::getResultBase(T *params)
418{
419 ANGLE_TRY(flush(true));
420 *params = static_cast<T>(mFinished ? GL_TRUE : GL_FALSE);
421 return gl::NoError();
422}
Geoff Langf9a6f082015-01-22 13:32:49 -0500423}