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"
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.
25 GetQueryTargetEnumString(GLenum 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";
39 MOZ_ASSERT(false, "Unknown query `target`.");
40 return "UNKNOWN_QUERY_TARGET";
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
)) {
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
)
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
;
75 // -------------------------------------------------------------------------
78 already_AddRefed
<WebGLQuery
>
79 WebGL2Context::CreateQuery()
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
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();
106 WebGL2Context::DeleteQuery(WebGLQuery
* query
)
114 if (query
->IsDeleted())
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
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();
136 WebGL2Context::IsQuery(WebGLQuery
* query
)
144 return (ValidateObjectAllowDeleted("isQuery", query
) &&
145 !query
->IsDeleted() &&
146 query
->HasEverBeenActive());
150 WebGL2Context::BeginQuery(GLenum target
, WebGLQuery
* query
)
155 WebGLRefPtr
<WebGLQuery
>* targetSlot
= GetQueryTargetSlot(target
);
157 ErrorInvalidEnum("beginQuery: unknown query target");
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.");
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
184 ErrorInvalidOperation("beginQuery: Query has been deleted.");
188 if (query
->HasEverBeenActive() &&
189 query
->mType
!= target
)
191 ErrorInvalidOperation("beginQuery: Target doesn't match with the query"
197 ErrorInvalidOperation("beginQuery: An other query already active.");
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
,
210 gl
->fBeginQuery(SimulateOcclusionQueryTarget(gl
, target
),
218 WebGL2Context::EndQuery(GLenum target
)
223 WebGLRefPtr
<WebGLQuery
>* targetSlot
= GetQueryTargetSlot(target
);
225 ErrorInvalidEnum("endQuery: unknown query target");
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
));
250 MakeContextCurrent();
252 if (target
== LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
) {
253 gl
->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
);
255 gl
->fEndQuery(SimulateOcclusionQueryTarget(gl
, target
));
258 *targetSlot
= nullptr;
261 already_AddRefed
<WebGLQuery
>
262 WebGL2Context::GetQuery(GLenum target
, GLenum pname
)
267 WebGLRefPtr
<WebGLQuery
>* targetSlot
= GetQueryTargetSlot(target
);
269 ErrorInvalidEnum("getQuery: unknown query target");
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.");
281 nsRefPtr
<WebGLQuery
> tmp
= targetSlot
->get();
286 WebGL2Context::GetQueryParameter(JSContext
*, WebGLQuery
* query
, GLenum pname
,
287 JS::MutableHandleValue retval
)
289 retval
.set(JS::NullValue());
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.");
305 if (query
->IsDeleted()) {
306 // See (spec getQueryObject 1)
307 ErrorInvalidOperation("getQueryObject: `query` has been deleted.");
311 if (query
->IsActive()) {
312 // See (spec getQueryObject 1)
313 ErrorInvalidOperation("getQueryObject: `query` is active.");
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.");
326 MakeContextCurrent();
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));
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
));
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));
354 ErrorInvalidEnum("getQueryObject: `pname` must be QUERY_RESULT{_AVAILABLE}.");