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/renderer/gl/FunctionsGL.h"
13 #include "libANGLE/renderer/gl/StateManagerGL.h"
14 
15 namespace
16 {
17 
MergeQueryResults(GLenum type,GLuint64 currentResult,GLuint64 newResult)18 GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult)
19 {
20     switch (type)
21     {
22         case GL_ANY_SAMPLES_PASSED:
23         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
24             return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
25 
26         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
27             return currentResult + newResult;
28 
29         case GL_TIME_ELAPSED:
30             return currentResult + newResult;
31 
32         case GL_TIMESTAMP:
33             return newResult;
34 
35         default:
36             UNREACHABLE();
37             return 0;
38     }
39 }
40 
41 }  // anonymous namespace
42 
43 namespace rx
44 {
45 
QueryGL(GLenum type,const FunctionsGL * functions,StateManagerGL * stateManager)46 QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager)
47     : QueryImpl(type),
48       mType(type),
49       mFunctions(functions),
50       mStateManager(stateManager),
51       mActiveQuery(0),
52       mPendingQueries(),
53       mResultSum(0)
54 {
55 }
56 
~QueryGL()57 QueryGL::~QueryGL()
58 {
59     mStateManager->deleteQuery(mActiveQuery);
60     mStateManager->onDeleteQueryObject(this);
61     while (!mPendingQueries.empty())
62     {
63         mStateManager->deleteQuery(mPendingQueries.front());
64         mPendingQueries.pop_front();
65     }
66 }
67 
begin()68 gl::Error QueryGL::begin()
69 {
70     mResultSum = 0;
71     mStateManager->onBeginQuery(this);
72     return resume();
73 }
74 
end()75 gl::Error QueryGL::end()
76 {
77     return pause();
78 }
79 
queryCounter()80 gl::Error QueryGL::queryCounter()
81 {
82     ASSERT(mType == GL_TIMESTAMP);
83 
84     // Directly create a query for the timestamp and add it to the pending query queue, as timestamp
85     // queries do not have the traditional begin/end block and never need to be paused/resumed
86     GLuint query;
87     mFunctions->genQueries(1, &query);
88     mFunctions->queryCounter(query, GL_TIMESTAMP);
89     mPendingQueries.push_back(query);
90 
91     return gl::Error(GL_NO_ERROR);
92 }
93 
94 template <typename T>
getResultBase(T * params)95 gl::Error QueryGL::getResultBase(T *params)
96 {
97     ASSERT(mActiveQuery == 0);
98 
99     gl::Error error = flush(true);
100     if (error.isError())
101     {
102         return error;
103     }
104 
105     ASSERT(mPendingQueries.empty());
106     *params = static_cast<T>(mResultSum);
107 
108     return gl::Error(GL_NO_ERROR);
109 }
110 
getResult(GLint * params)111 gl::Error QueryGL::getResult(GLint *params)
112 {
113     return getResultBase(params);
114 }
115 
getResult(GLuint * params)116 gl::Error QueryGL::getResult(GLuint *params)
117 {
118     return getResultBase(params);
119 }
120 
getResult(GLint64 * params)121 gl::Error QueryGL::getResult(GLint64 *params)
122 {
123     return getResultBase(params);
124 }
125 
getResult(GLuint64 * params)126 gl::Error QueryGL::getResult(GLuint64 *params)
127 {
128     return getResultBase(params);
129 }
130 
isResultAvailable(bool * available)131 gl::Error QueryGL::isResultAvailable(bool *available)
132 {
133     ASSERT(mActiveQuery == 0);
134 
135     gl::Error error = flush(false);
136     if (error.isError())
137     {
138         return error;
139     }
140 
141     *available = mPendingQueries.empty();
142     return gl::Error(GL_NO_ERROR);
143 }
144 
pause()145 gl::Error QueryGL::pause()
146 {
147     if (mActiveQuery != 0)
148     {
149         mStateManager->endQuery(mType, mActiveQuery);
150 
151         mPendingQueries.push_back(mActiveQuery);
152         mActiveQuery = 0;
153     }
154 
155     // Flush to make sure the pending queries don't add up too much.
156     gl::Error error = flush(false);
157     if (error.isError())
158     {
159         return error;
160     }
161 
162     return gl::Error(GL_NO_ERROR);
163 }
164 
resume()165 gl::Error QueryGL::resume()
166 {
167     if (mActiveQuery == 0)
168     {
169         // Flush to make sure the pending queries don't add up too much.
170         gl::Error error = flush(false);
171         if (error.isError())
172         {
173             return error;
174         }
175 
176         mFunctions->genQueries(1, &mActiveQuery);
177         mStateManager->beginQuery(mType, mActiveQuery);
178     }
179 
180     return gl::Error(GL_NO_ERROR);
181 }
182 
flush(bool force)183 gl::Error QueryGL::flush(bool force)
184 {
185     while (!mPendingQueries.empty())
186     {
187         GLuint id = mPendingQueries.front();
188         if (!force)
189         {
190             GLuint resultAvailable = 0;
191             mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
192             if (resultAvailable == GL_FALSE)
193             {
194                 return gl::Error(GL_NO_ERROR);
195             }
196         }
197 
198         // Even though getQueryObjectui64v was introduced for timer queries, there is nothing in the
199         // standard that says that it doesn't work for any other queries. It also passes on all the
200         // trybots, so we use it if it is available
201         if (mFunctions->getQueryObjectui64v != nullptr)
202         {
203             GLuint64 result = 0;
204             mFunctions->getQueryObjectui64v(id, GL_QUERY_RESULT, &result);
205             mResultSum = MergeQueryResults(mType, mResultSum, result);
206         }
207         else
208         {
209             GLuint result = 0;
210             mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
211             mResultSum = MergeQueryResults(mType, mResultSum, static_cast<GLuint64>(result));
212         }
213 
214         mStateManager->deleteQuery(id);
215 
216         mPendingQueries.pop_front();
217     }
218 
219     return gl::Error(GL_NO_ERROR);
220 }
221 
222 }
223