Bumping manifests a=b2g-bump
[gecko.git] / dom / canvas / WebGL2ContextQueries.cpp
blob8a5660e3cdd24c0033b2a3a3436d3d368e15cf81
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/. */
6 #include "WebGL2Context.h"
7 #include "GLContext.h"
8 #include "WebGLQuery.h"
10 using namespace mozilla;
11 using namespace mozilla::dom;
14 * We fake ANY_SAMPLES_PASSED and ANY_SAMPLES_PASSED_CONSERVATIVE with
15 * SAMPLES_PASSED on desktop.
17 * OpenGL ES 3.0 spec 4.1.6:
18 * If the target of the query is ANY_SAMPLES_PASSED_CONSERVATIVE, an
19 * implementation may choose to use a less precise version of the test which
20 * can additionally set the samples-boolean state to TRUE in some other
21 * implementation-dependent cases.
24 static const char*
25 GetQueryTargetEnumString(GLenum target)
27 switch (target)
29 case LOCAL_GL_ANY_SAMPLES_PASSED:
30 return "ANY_SAMPLES_PASSED";
31 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
32 return "ANY_SAMPLES_PASSED_CONSERVATIVE";
33 case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
34 return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
35 default:
36 break;
39 MOZ_ASSERT(false, "Unknown query `target`.");
40 return "UNKNOWN_QUERY_TARGET";
43 static inline GLenum
44 SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
46 MOZ_ASSERT(target == LOCAL_GL_ANY_SAMPLES_PASSED ||
47 target == LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
48 "unknown occlusion query target");
50 if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) {
51 return target;
52 } else if (gl->IsSupported(gl::GLFeature::occlusion_query2)) {
53 return LOCAL_GL_ANY_SAMPLES_PASSED;
56 return LOCAL_GL_SAMPLES_PASSED;
59 WebGLRefPtr<WebGLQuery>*
60 WebGLContext::GetQueryTargetSlot(GLenum target)
62 switch (target) {
63 case LOCAL_GL_ANY_SAMPLES_PASSED:
64 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
65 return &mActiveOcclusionQuery;
67 case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
68 return &mActiveTransformFeedbackQuery;
71 return nullptr;
75 // -------------------------------------------------------------------------
76 // Query Objects
78 already_AddRefed<WebGLQuery>
79 WebGL2Context::CreateQuery()
81 if (IsContextLost())
82 return nullptr;
84 if (mActiveOcclusionQuery && !gl->IsGLES()) {
85 /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
87 * Calling either GenQueriesARB or DeleteQueriesARB while any query of
88 * any target is active causes an INVALID_OPERATION error to be
89 * generated.
91 GenerateWarning("createQuery: The WebGL 2 prototype might generate"
92 " INVALID_OPERATION when creating a query object while"
93 " one other is active.");
95 * We *need* to lock webgl2 to GL>=3.0 on desktop, but we don't have a
96 * good mechanism to do this yet. See bug 898404.
100 nsRefPtr<WebGLQuery> globj = new WebGLQuery(this);
102 return globj.forget();
105 void
106 WebGL2Context::DeleteQuery(WebGLQuery* query)
108 if (IsContextLost())
109 return;
111 if (!query)
112 return;
114 if (query->IsDeleted())
115 return;
117 if (query->IsActive())
118 EndQuery(query->mType);
120 if (mActiveOcclusionQuery && !gl->IsGLES()) {
121 /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
123 * Calling either GenQueriesARB or DeleteQueriesARB while any query of
124 * any target is active causes an INVALID_OPERATION error to be
125 * generated.
127 GenerateWarning("deleteQuery: The WebGL 2 prototype might generate"
128 " INVALID_OPERATION when deleting a query object while"
129 " one other is active.");
132 query->RequestDelete();
135 bool
136 WebGL2Context::IsQuery(WebGLQuery* query)
138 if (IsContextLost())
139 return false;
141 if (!query)
142 return false;
144 return (ValidateObjectAllowDeleted("isQuery", query) &&
145 !query->IsDeleted() &&
146 query->HasEverBeenActive());
149 void
150 WebGL2Context::BeginQuery(GLenum target, WebGLQuery* query)
152 if (IsContextLost())
153 return;
155 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
156 if (!targetSlot) {
157 ErrorInvalidEnum("beginQuery: unknown query target");
158 return;
161 if (!query) {
162 /* From GLES's EXT_occlusion_query_boolean:
163 * BeginQueryEXT sets the active query object name for the query
164 * type given by <target> to <id>. If BeginQueryEXT is called with
165 * an <id> of zero, if the active query object name for <target> is
166 * non-zero (for the targets ANY_SAMPLES_PASSED_EXT and
167 * ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the active query for
168 * either target is non-zero), if <id> is the name of an existing
169 * query object whose type does not match <target>, or if <id> is
170 * the active query object name for any query type, the error
171 * INVALID_OPERATION is generated.
173 ErrorInvalidOperation("beginQuery: Query should not be null.");
174 return;
177 if (query->IsDeleted()) {
178 /* From GLES's EXT_occlusion_query_boolean:
179 * BeginQueryEXT fails and an INVALID_OPERATION error is generated
180 * if <id> is not a name returned from a previous call to
181 * GenQueriesEXT, or if such a name has since been deleted with
182 * DeleteQueriesEXT.
184 ErrorInvalidOperation("beginQuery: Query has been deleted.");
185 return;
188 if (query->HasEverBeenActive() &&
189 query->mType != target)
191 ErrorInvalidOperation("beginQuery: Target doesn't match with the query"
192 " type.");
193 return;
196 if (*targetSlot) {
197 ErrorInvalidOperation("beginQuery: An other query already active.");
198 return;
201 if (!query->HasEverBeenActive())
202 query->mType = target;
204 MakeContextCurrent();
206 if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
207 gl->fBeginQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
208 query->mGLName);
209 } else {
210 gl->fBeginQuery(SimulateOcclusionQueryTarget(gl, target),
211 query->mGLName);
214 *targetSlot = query;
217 void
218 WebGL2Context::EndQuery(GLenum target)
220 if (IsContextLost())
221 return;
223 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
224 if (!targetSlot) {
225 ErrorInvalidEnum("endQuery: unknown query target");
226 return;
229 if (!*targetSlot ||
230 target != (*targetSlot)->mType)
232 /* From GLES's EXT_occlusion_query_boolean:
233 * marks the end of the sequence of commands to be tracked for the
234 * query type given by <target>. The active query object for
235 * <target> is updated to indicate that query results are not
236 * available, and the active query object name for <target> is reset
237 * to zero. When the commands issued prior to EndQueryEXT have
238 * completed and a final query result is available, the query object
239 * active when EndQueryEXT is called is updated by the GL. The query
240 * object is updated to indicate that the query results are
241 * available and to contain the query result. If the active query
242 * object name for <target> is zero when EndQueryEXT is called, the
243 * error INVALID_OPERATION is generated.
245 ErrorInvalidOperation("endQuery: There is no active query of type %s.",
246 GetQueryTargetEnumString(target));
247 return;
250 MakeContextCurrent();
252 if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
253 gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
254 } else {
255 gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
258 *targetSlot = nullptr;
261 already_AddRefed<WebGLQuery>
262 WebGL2Context::GetQuery(GLenum target, GLenum pname)
264 if (IsContextLost())
265 return nullptr;
267 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
268 if (!targetSlot) {
269 ErrorInvalidEnum("getQuery: unknown query target");
270 return nullptr;
273 if (pname != LOCAL_GL_CURRENT_QUERY) {
274 /* OpenGL ES 3.0 spec 6.1.7:
275 * pname must be CURRENT_QUERY.
277 ErrorInvalidEnum("getQuery: `pname` must be CURRENT_QUERY.");
278 return nullptr;
281 nsRefPtr<WebGLQuery> tmp = targetSlot->get();
282 return tmp.forget();
285 void
286 WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
287 JS::MutableHandleValue retval)
289 retval.set(JS::NullValue());
291 if (IsContextLost())
292 return;
294 if (!query) {
295 /* OpenGL ES 3.0 spec 6.1.7 (spec getQueryObject 1):
296 * If id is not the name of a query object, or if the query object
297 * named by id is currently active, then an INVALID_OPERATION error
298 * is generated. pname must be QUERY_RESULT or
299 * QUERY_RESULT_AVAILABLE.
301 ErrorInvalidOperation("getQueryObject: `query` should not be null.");
302 return;
305 if (query->IsDeleted()) {
306 // See (spec getQueryObject 1)
307 ErrorInvalidOperation("getQueryObject: `query` has been deleted.");
308 return;
311 if (query->IsActive()) {
312 // See (spec getQueryObject 1)
313 ErrorInvalidOperation("getQueryObject: `query` is active.");
314 return;
317 if (!query->HasEverBeenActive()) {
318 /* See (spec getQueryObject 1)
319 * If this instance of WebGLQuery has never been active before, that
320 * mean that query->mGLName is not a query object yet.
322 ErrorInvalidOperation("getQueryObject: `query` has never been active.");
323 return;
326 MakeContextCurrent();
327 GLuint returned = 0;
328 switch (pname) {
329 case LOCAL_GL_QUERY_RESULT_AVAILABLE:
330 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
331 retval.set(JS::BooleanValue(returned != 0));
332 return;
334 case LOCAL_GL_QUERY_RESULT:
335 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT, &returned);
337 if (query->mType == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
338 retval.set(JS::NumberValue(returned));
339 return;
343 * test (returned != 0) is important because ARB_occlusion_query on desktop drivers
344 * return the number of samples drawed when the OpenGL ES extension
345 * ARB_occlusion_query_boolean return only a boolean if a sample has been drawed.
347 retval.set(JS::BooleanValue(returned != 0));
348 return;
350 default:
351 break;
354 ErrorInvalidEnum("getQueryObject: `pname` must be QUERY_RESULT{_AVAILABLE}.");