Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; 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 "WebGLQuery.h"
7 :
8 : #include "gfxPrefs.h"
9 : #include "GLContext.h"
10 : #include "mozilla/dom/WebGL2RenderingContextBinding.h"
11 : #include "nsContentUtils.h"
12 : #include "WebGLContext.h"
13 :
14 : namespace mozilla {
15 :
16 0 : class AvailableRunnable final : public Runnable
17 : {
18 : const RefPtr<WebGLQuery> mQuery;
19 :
20 : public:
21 0 : explicit AvailableRunnable(WebGLQuery* query)
22 0 : : Runnable("AvailableRunnable")
23 0 : , mQuery(query)
24 : {
25 0 : }
26 :
27 0 : NS_IMETHOD Run() override
28 : {
29 0 : mQuery->mCanBeAvailable = true;
30 0 : return NS_OK;
31 : }
32 : };
33 :
34 : ////
35 :
36 : static GLuint
37 0 : GenQuery(gl::GLContext* gl)
38 : {
39 0 : gl->MakeCurrent();
40 :
41 0 : GLuint ret = 0;
42 0 : gl->fGenQueries(1, &ret);
43 0 : return ret;
44 : }
45 :
46 0 : WebGLQuery::WebGLQuery(WebGLContext* webgl)
47 : : WebGLRefCountedObject(webgl)
48 0 : , mGLName(GenQuery(mContext->gl))
49 : , mTarget(0)
50 : , mActiveSlot(nullptr)
51 0 : , mCanBeAvailable(false)
52 : {
53 0 : mContext->mQueries.insertBack(this);
54 0 : }
55 :
56 : void
57 0 : WebGLQuery::Delete()
58 : {
59 0 : mContext->MakeContextCurrent();
60 0 : mContext->gl->fDeleteQueries(1, &mGLName);
61 0 : LinkedListElement<WebGLQuery>::removeFrom(mContext->mQueries);
62 0 : }
63 :
64 : ////
65 :
66 : static GLenum
67 0 : TargetForDriver(const gl::GLContext* gl, GLenum target)
68 : {
69 0 : switch (target) {
70 : case LOCAL_GL_ANY_SAMPLES_PASSED:
71 : case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
72 0 : break;
73 :
74 : default:
75 0 : return target;
76 : }
77 :
78 0 : if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
79 0 : return target;
80 :
81 0 : if (gl->IsSupported(gl::GLFeature::occlusion_query2))
82 0 : return LOCAL_GL_ANY_SAMPLES_PASSED;
83 :
84 0 : return LOCAL_GL_SAMPLES_PASSED;
85 : }
86 :
87 : void
88 0 : WebGLQuery::BeginQuery(GLenum target, WebGLRefPtr<WebGLQuery>& slot)
89 : {
90 0 : const char funcName[] = "beginQuery";
91 :
92 0 : if (mTarget && target != mTarget) {
93 0 : mContext->ErrorInvalidOperation("%s: Queries cannot change targets.", funcName);
94 0 : return;
95 : }
96 :
97 : ////
98 :
99 0 : mTarget = target;
100 0 : mActiveSlot = &slot;
101 0 : *mActiveSlot = this;
102 :
103 : ////
104 :
105 0 : const auto& gl = mContext->gl;
106 0 : gl->MakeCurrent();
107 :
108 0 : const auto driverTarget = TargetForDriver(gl, mTarget);
109 0 : gl->fBeginQuery(driverTarget, mGLName);
110 : }
111 :
112 : void
113 0 : WebGLQuery::EndQuery()
114 : {
115 0 : *mActiveSlot = nullptr;
116 0 : mActiveSlot = nullptr;
117 0 : mCanBeAvailable = false;
118 :
119 : ////
120 :
121 0 : const auto& gl = mContext->gl;
122 0 : gl->MakeCurrent();
123 :
124 0 : const auto driverTarget = TargetForDriver(gl, mTarget);
125 0 : gl->fEndQuery(driverTarget);
126 :
127 : ////
128 :
129 0 : NS_DispatchToCurrentThread(new AvailableRunnable(this));
130 0 : }
131 :
132 : void
133 0 : WebGLQuery::GetQueryParameter(GLenum pname, JS::MutableHandleValue retval) const
134 : {
135 0 : const char funcName[] = "getQueryParameter";
136 :
137 0 : switch (pname) {
138 : case LOCAL_GL_QUERY_RESULT_AVAILABLE:
139 : case LOCAL_GL_QUERY_RESULT:
140 0 : break;
141 :
142 : default:
143 0 : mContext->ErrorInvalidEnumArg(funcName, "pname", pname);
144 0 : return;
145 : }
146 :
147 0 : if (!mTarget) {
148 0 : mContext->ErrorInvalidOperation("%s: Query has never been active.", funcName);
149 0 : return;
150 : }
151 :
152 0 : if (mActiveSlot)
153 0 : return mContext->ErrorInvalidOperation("%s: Query is still active.", funcName);
154 :
155 : // End of validation
156 : ////
157 :
158 : // We must usually wait for an event loop before the query can be available.
159 0 : const bool canBeAvailable = (mCanBeAvailable || gfxPrefs::WebGLImmediateQueries());
160 0 : if (!canBeAvailable) {
161 0 : if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
162 0 : retval.set(JS::BooleanValue(false));
163 : }
164 0 : return;
165 : }
166 :
167 0 : const auto& gl = mContext->gl;
168 0 : gl->MakeCurrent();
169 :
170 0 : uint64_t val = 0;
171 0 : switch (pname) {
172 : case LOCAL_GL_QUERY_RESULT_AVAILABLE:
173 0 : gl->fGetQueryObjectuiv(mGLName, pname, (GLuint*)&val);
174 0 : retval.set(JS::BooleanValue(bool(val)));
175 0 : return;
176 :
177 : case LOCAL_GL_QUERY_RESULT:
178 0 : switch (mTarget) {
179 : case LOCAL_GL_TIME_ELAPSED_EXT:
180 : case LOCAL_GL_TIMESTAMP_EXT:
181 0 : if (mContext->Has64BitTimestamps()) {
182 0 : gl->fGetQueryObjectui64v(mGLName, pname, &val);
183 0 : break;
184 : }
185 : MOZ_FALLTHROUGH;
186 :
187 : default:
188 0 : gl->fGetQueryObjectuiv(mGLName, LOCAL_GL_QUERY_RESULT, (GLuint*)&val);
189 0 : break;
190 : }
191 :
192 0 : switch (mTarget) {
193 : case LOCAL_GL_ANY_SAMPLES_PASSED:
194 : case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
195 0 : retval.set(JS::BooleanValue(bool(val)));
196 0 : break;
197 :
198 : case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
199 : case LOCAL_GL_TIME_ELAPSED_EXT:
200 : case LOCAL_GL_TIMESTAMP_EXT:
201 0 : retval.set(JS::NumberValue(val));
202 0 : break;
203 :
204 : default:
205 0 : MOZ_CRASH("Bad `mTarget`.");
206 : }
207 0 : return;
208 :
209 : default:
210 0 : MOZ_CRASH("Bad `pname`.");
211 : }
212 : }
213 :
214 : bool
215 0 : WebGLQuery::IsQuery() const
216 : {
217 0 : MOZ_ASSERT(!IsDeleted());
218 :
219 0 : if (!mTarget)
220 0 : return false;
221 :
222 0 : return true;
223 : }
224 :
225 : void
226 0 : WebGLQuery::DeleteQuery()
227 : {
228 0 : MOZ_ASSERT(!IsDeleteRequested());
229 :
230 0 : if (mActiveSlot) {
231 0 : EndQuery();
232 : }
233 :
234 0 : RequestDelete();
235 0 : }
236 :
237 : void
238 0 : WebGLQuery::QueryCounter(const char* funcName, GLenum target)
239 : {
240 0 : if (target != LOCAL_GL_TIMESTAMP_EXT) {
241 0 : mContext->ErrorInvalidEnum("%s: `target` must be TIMESTAMP_EXT.", funcName);
242 0 : return;
243 : }
244 :
245 0 : if (mTarget && target != mTarget) {
246 0 : mContext->ErrorInvalidOperation("%s: Queries cannot change targets.", funcName);
247 0 : return;
248 : }
249 :
250 0 : mTarget = target;
251 0 : mCanBeAvailable = false;
252 :
253 0 : const auto& gl = mContext->gl;
254 0 : gl->MakeCurrent();
255 0 : gl->fQueryCounter(mGLName, mTarget);
256 :
257 0 : NS_DispatchToCurrentThread(new AvailableRunnable(this));
258 : }
259 :
260 : ////
261 :
262 : JSObject*
263 0 : WebGLQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
264 : {
265 0 : return dom::WebGLQueryBinding::Wrap(cx, this, givenProto);
266 : }
267 :
268 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLQuery)
269 :
270 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLQuery, AddRef)
271 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLQuery, Release)
272 :
273 : } // namespace mozilla
|