Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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 "WebGLContext.h"
7 #include "WebGLQuery.h"
8 #include "GLContext.h"
10 using namespace mozilla;
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 */
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 }
37 MOZ_ASSERT(false, "Unknown query `target`.");
38 return "UNKNOWN_QUERY_TARGET";
39 }
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");
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 }
54 return LOCAL_GL_SAMPLES_PASSED;
55 }
57 already_AddRefed<WebGLQuery>
58 WebGLContext::CreateQuery()
59 {
60 if (IsContextLost())
61 return nullptr;
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 }
77 nsRefPtr<WebGLQuery> globj = new WebGLQuery(this);
79 return globj.forget();
80 }
82 void
83 WebGLContext::DeleteQuery(WebGLQuery *query)
84 {
85 if (IsContextLost())
86 return;
88 if (!query)
89 return;
91 if (query->IsDeleted())
92 return;
94 if (query->IsActive()) {
95 EndQuery(query->mType);
96 }
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 }
108 query->RequestDelete();
109 }
111 void
112 WebGLContext::BeginQuery(GLenum target, WebGLQuery *query)
113 {
114 if (IsContextLost())
115 return;
117 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "beginQuery");
118 if (!targetSlot) {
119 return;
120 }
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 }
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 }
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 }
158 if (*targetSlot) {
159 /*
160 * See SPECS BeginQuery.1
161 */
162 ErrorInvalidOperation("beginQuery: an other query already active");
163 return;
164 }
166 if (!query->HasEverBeenActive()) {
167 query->mType = target;
168 }
170 MakeContextCurrent();
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 }
178 *targetSlot = query;
179 }
181 void
182 WebGLContext::EndQuery(GLenum target)
183 {
184 if (IsContextLost())
185 return;
187 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "endQuery");
188 if (!targetSlot) {
189 return;
190 }
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 }
212 MakeContextCurrent();
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 }
220 *targetSlot = nullptr;
221 }
223 bool
224 WebGLContext::IsQuery(WebGLQuery *query)
225 {
226 if (IsContextLost())
227 return false;
229 if (!query)
230 return false;
232 return ValidateObjectAllowDeleted("isQuery", query) &&
233 !query->IsDeleted() &&
234 query->HasEverBeenActive();
235 }
237 already_AddRefed<WebGLQuery>
238 WebGLContext::GetQuery(GLenum target, GLenum pname)
239 {
240 if (IsContextLost())
241 return nullptr;
243 WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "getQuery");
244 if (!targetSlot) {
245 return nullptr;
246 }
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 }
256 nsRefPtr<WebGLQuery> tmp = targetSlot->get();
257 return tmp.forget();
258 }
260 JS::Value
261 WebGLContext::GetQueryObject(JSContext* cx, WebGLQuery *query, GLenum pname)
262 {
263 if (IsContextLost())
264 return JS::NullValue();
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 }
276 if (query->IsDeleted()) {
277 // See (spec getQueryObject 1)
278 ErrorInvalidOperation("getQueryObject: query has been deleted");
279 return JS::NullValue();
280 }
282 if (query->IsActive()) {
283 // See (spec getQueryObject 1)
284 ErrorInvalidOperation("getQueryObject: query is active");
285 return JS::NullValue();
286 }
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 }
297 switch (pname)
298 {
299 case LOCAL_GL_QUERY_RESULT_AVAILABLE:
300 {
301 GLuint returned = 0;
303 MakeContextCurrent();
304 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
306 return JS::BooleanValue(returned != 0);
307 }
309 case LOCAL_GL_QUERY_RESULT:
310 {
311 GLuint returned = 0;
313 MakeContextCurrent();
314 gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT, &returned);
316 if (query->mType == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
317 return JS::NumberValue(uint32_t(returned));
318 }
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 }
328 default:
329 break;
330 }
332 ErrorInvalidEnum("getQueryObject: pname must be QUERY_RESULT{_AVAILABLE}");
333 return JS::NullValue();
334 }
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 }
347 ErrorInvalidEnum("%s: unknown query target", infos);
348 return nullptr;
349 }