content/canvas/src/WebGLContextAsyncQueries.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:7283ac11aed9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "WebGLContext.h"
7 #include "WebGLQuery.h"
8 #include "GLContext.h"
9
10 using namespace mozilla;
11
12 /*
13 * We fake ANY_SAMPLES_PASSED and ANY_SAMPLES_PASSED_CONSERVATIVE with
14 * SAMPLES_PASSED on desktop.
15 *
16 * OpenGL ES 3.0 spec 4.1.6
17 * If the target of the query is ANY_SAMPLES_PASSED_CONSERVATIVE, an implementation
18 * may choose to use a less precise version of the test which can additionally set
19 * the samples-boolean state to TRUE in some other implementation-dependent cases.
20 */
21
22 static const char*
23 GetQueryTargetEnumString(GLenum target)
24 {
25 switch (target)
26 {
27 case LOCAL_GL_ANY_SAMPLES_PASSED:
28 return "ANY_SAMPLES_PASSED";
29 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
30 return "ANY_SAMPLES_PASSED_CONSERVATIVE";
31 case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
32 return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
33 default:
34 break;
35 }
36
37 MOZ_ASSERT(false, "Unknown query `target`.");
38 return "UNKNOWN_QUERY_TARGET";
39 }
40
41 static inline GLenum
42 SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
43 {
44 MOZ_ASSERT(target == LOCAL_GL_ANY_SAMPLES_PASSED ||
45 target == LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
46 "unknown occlusion query target");
47
48 if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) {
49 return target;
50 } else if (gl->IsSupported(gl::GLFeature::occlusion_query2)) {
51 return LOCAL_GL_ANY_SAMPLES_PASSED;
52 }
53
54 return LOCAL_GL_SAMPLES_PASSED;
55 }
56
57 already_AddRefed<WebGLQuery>
58 WebGLContext::CreateQuery()
59 {
60 if (IsContextLost())
61 return nullptr;
62
63 if (mActiveOcclusionQuery && !gl->IsGLES()) {
64 /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
65 * Calling either GenQueriesARB or DeleteQueriesARB while any query of
66 * any target is active causes an INVALID_OPERATION error to be
67 * generated.
68 */
69 GenerateWarning("createQuery: the WebGL 2 prototype might generate INVALID_OPERATION"
70 "when creating a query object while one other is active.");
71 /*
72 * We *need* to lock webgl2 to GL>=3.0 on desktop, but we don't have a good
73 * mechanism to do this yet. See bug 898404.
74 */
75 }
76
77 nsRefPtr<WebGLQuery> globj = new WebGLQuery(this);
78
79 return globj.forget();
80 }
81
82 void
83 WebGLContext::DeleteQuery(WebGLQuery *query)
84 {
85 if (IsContextLost())
86 return;
87
88 if (!query)
89 return;
90
91 if (query->IsDeleted())
92 return;
93
94 if (query->IsActive()) {
95 EndQuery(query->mType);
96 }
97
98 if (mActiveOcclusionQuery && !gl->IsGLES()) {
99 /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
100 * Calling either GenQueriesARB or DeleteQueriesARB while any query of
101 * any target is active causes an INVALID_OPERATION error to be
102 * generated.
103 */
104 GenerateWarning("deleteQuery: the WebGL 2 prototype might generate INVALID_OPERATION"
105 "when deleting a query object while one other is active.");
106 }
107
108 query->RequestDelete();
109 }
110
111 void
112 WebGLContext::BeginQuery(GLenum target, WebGLQuery *query)
113 {
114 if (IsContextLost())
115 return;
116
117 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "beginQuery");
118 if (!targetSlot) {
119 return;
120 }
121
122 if (!query) {
123 /* SPECS BeginQuery.1
124 * http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
125 * BeginQueryEXT sets the active query object name for the query type given
126 * by <target> to <id>. If BeginQueryEXT is called with an <id> of zero, if
127 * the active query object name for <target> is non-zero (for the targets
128 * ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the
129 * active query for either target is non-zero), if <id> is the name of an
130 * existing query object whose type does not match <target>, or if <id> is the
131 * active query object name for any query type, the error INVALID_OPERATION is
132 * generated.
133 */
134 ErrorInvalidOperation("beginQuery: query should not be null");
135 return;
136 }
137
138 if (query->IsDeleted()) {
139 /* http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
140 * BeginQueryEXT fails and an INVALID_OPERATION error is generated if <id>
141 * is not a name returned from a previous call to GenQueriesEXT, or if such
142 * a name has since been deleted with DeleteQueriesEXT.
143 */
144 ErrorInvalidOperation("beginQuery: query has been deleted");
145 return;
146 }
147
148 if (query->HasEverBeenActive() &&
149 query->mType != target)
150 {
151 /*
152 * See SPECS BeginQuery.1
153 */
154 ErrorInvalidOperation("beginQuery: target doesn't match with the query type");
155 return;
156 }
157
158 if (*targetSlot) {
159 /*
160 * See SPECS BeginQuery.1
161 */
162 ErrorInvalidOperation("beginQuery: an other query already active");
163 return;
164 }
165
166 if (!query->HasEverBeenActive()) {
167 query->mType = target;
168 }
169
170 MakeContextCurrent();
171
172 if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
173 gl->fBeginQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->mGLName);
174 } else {
175 gl->fBeginQuery(SimulateOcclusionQueryTarget(gl, target), query->mGLName);
176 }
177
178 *targetSlot = query;
179 }
180
181 void
182 WebGLContext::EndQuery(GLenum target)
183 {
184 if (IsContextLost())
185 return;
186
187 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "endQuery");
188 if (!targetSlot) {
189 return;
190 }
191
192 if (!*targetSlot ||
193 target != (*targetSlot)->mType)
194 {
195 /* http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
196 * marks the end of the sequence of commands to be tracked for the query type
197 * given by <target>. The active query object for <target> is updated to
198 * indicate that query results are not available, and the active query object
199 * name for <target> is reset to zero. When the commands issued prior to
200 * EndQueryEXT have completed and a final query result is available, the
201 * query object active when EndQueryEXT is called is updated by the GL. The
202 * query object is updated to indicate that the query results are available
203 * and to contain the query result. If the active query object name for
204 * <target> is zero when EndQueryEXT is called, the error INVALID_OPERATION
205 * is generated.
206 */
207 ErrorInvalidOperation("endQuery: There is no active query of type %s.",
208 GetQueryTargetEnumString(target));
209 return;
210 }
211
212 MakeContextCurrent();
213
214 if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
215 gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
216 } else {
217 gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
218 }
219
220 *targetSlot = nullptr;
221 }
222
223 bool
224 WebGLContext::IsQuery(WebGLQuery *query)
225 {
226 if (IsContextLost())
227 return false;
228
229 if (!query)
230 return false;
231
232 return ValidateObjectAllowDeleted("isQuery", query) &&
233 !query->IsDeleted() &&
234 query->HasEverBeenActive();
235 }
236
237 already_AddRefed<WebGLQuery>
238 WebGLContext::GetQuery(GLenum target, GLenum pname)
239 {
240 if (IsContextLost())
241 return nullptr;
242
243 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "getQuery");
244 if (!targetSlot) {
245 return nullptr;
246 }
247
248 if (pname != LOCAL_GL_CURRENT_QUERY) {
249 /* OpenGL ES 3.0 spec 6.1.7
250 * pname must be CURRENT_QUERY.
251 */
252 ErrorInvalidEnum("getQuery: pname must be CURRENT_QUERY");
253 return nullptr;
254 }
255
256 nsRefPtr<WebGLQuery> tmp = targetSlot->get();
257 return tmp.forget();
258 }
259
260 JS::Value
261 WebGLContext::GetQueryObject(JSContext* cx, WebGLQuery *query, GLenum pname)
262 {
263 if (IsContextLost())
264 return JS::NullValue();
265
266 if (!query) {
267 /* OpenGL ES 3.0 spec 6.1.7 (spec getQueryObject 1)
268 * If id is not the name of a query object, or if the query object named by id is
269 * currently active, then an INVALID_OPERATION error is generated. pname must be
270 * QUERY_RESULT or QUERY_RESULT_AVAILABLE.
271 */
272 ErrorInvalidOperation("getQueryObject: query should not be null");
273 return JS::NullValue();
274 }
275
276 if (query->IsDeleted()) {
277 // See (spec getQueryObject 1)
278 ErrorInvalidOperation("getQueryObject: query has been deleted");
279 return JS::NullValue();
280 }
281
282 if (query->IsActive()) {
283 // See (spec getQueryObject 1)
284 ErrorInvalidOperation("getQueryObject: query is active");
285 return JS::NullValue();
286 }
287
288 if (!query->HasEverBeenActive()) {
289 /* See (spec getQueryObject 1)
290 * If this instance of WebGLQuery has never been active before, that mean that
291 * query->mGLName is not a query object yet.
292 */
293 ErrorInvalidOperation("getQueryObject: query has never been active");
294 return JS::NullValue();
295 }
296
297 switch (pname)
298 {
299 case LOCAL_GL_QUERY_RESULT_AVAILABLE:
300 {
301 GLuint returned = 0;
302
303 MakeContextCurrent();
304 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
305
306 return JS::BooleanValue(returned != 0);
307 }
308
309 case LOCAL_GL_QUERY_RESULT:
310 {
311 GLuint returned = 0;
312
313 MakeContextCurrent();
314 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT, &returned);
315
316 if (query->mType == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
317 return JS::NumberValue(uint32_t(returned));
318 }
319
320 /*
321 * test (returned != 0) is important because ARB_occlusion_query on desktop drivers
322 * return the number of samples drawed when the OpenGL ES extension
323 * ARB_occlusion_query_boolean return only a boolean if a sample has been drawed.
324 */
325 return JS::BooleanValue(returned != 0);
326 }
327
328 default:
329 break;
330 }
331
332 ErrorInvalidEnum("getQueryObject: pname must be QUERY_RESULT{_AVAILABLE}");
333 return JS::NullValue();
334 }
335
336 WebGLRefPtr<WebGLQuery>*
337 WebGLContext::GetQueryTargetSlot(GLenum target, const char* infos)
338 {
339 switch (target) {
340 case LOCAL_GL_ANY_SAMPLES_PASSED:
341 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
342 return &mActiveOcclusionQuery;
343 case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
344 return &mActiveTransformFeedbackQuery;
345 }
346
347 ErrorInvalidEnum("%s: unknown query target", infos);
348 return nullptr;
349 }
350
351

mercurial