1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 "GLContext.h"
9 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
10 #include "mozilla/StaticPrefs_webgl.h"
11 #include "nsContentUtils.h"
12 #include "WebGLContext.h"
13
14 namespace mozilla {
15
16 ////
17
GenQuery(gl::GLContext * gl)18 static GLuint GenQuery(gl::GLContext* gl) {
19 GLuint ret = 0;
20 gl->fGenQueries(1, &ret);
21 return ret;
22 }
23
WebGLQuery(WebGLContext * webgl)24 WebGLQuery::WebGLQuery(WebGLContext* webgl)
25 : WebGLContextBoundObject(webgl),
26 mGLName(GenQuery(mContext->gl)),
27 mTarget(0),
28 mActiveSlot(nullptr) {}
29
~WebGLQuery()30 WebGLQuery::~WebGLQuery() {
31 if (!mContext) return;
32 mContext->gl->fDeleteQueries(1, &mGLName);
33 }
34
35 ////
36
TargetForDriver(const gl::GLContext * gl,GLenum target)37 static GLenum TargetForDriver(const gl::GLContext* gl, GLenum target) {
38 switch (target) {
39 case LOCAL_GL_ANY_SAMPLES_PASSED:
40 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
41 break;
42
43 default:
44 return target;
45 }
46
47 if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) return target;
48
49 if (gl->IsSupported(gl::GLFeature::occlusion_query2))
50 return LOCAL_GL_ANY_SAMPLES_PASSED;
51
52 return LOCAL_GL_SAMPLES_PASSED;
53 }
54
BeginQuery(GLenum target,RefPtr<WebGLQuery> & slot)55 void WebGLQuery::BeginQuery(GLenum target, RefPtr<WebGLQuery>& slot) {
56 mTarget = target;
57 mActiveSlot = &slot;
58 *mActiveSlot = this;
59
60 ////
61
62 const auto& gl = mContext->gl;
63
64 const auto driverTarget = TargetForDriver(gl, mTarget);
65 gl->fBeginQuery(driverTarget, mGLName);
66 }
67
EndQuery()68 void WebGLQuery::EndQuery() {
69 *mActiveSlot = nullptr;
70 mActiveSlot = nullptr;
71 mCanBeAvailable = false;
72
73 ////
74
75 const auto& gl = mContext->gl;
76
77 const auto driverTarget = TargetForDriver(gl, mTarget);
78 gl->fEndQuery(driverTarget);
79
80 ////
81
82 const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
83 availRunnable->mQueries.push_back(this);
84 }
85
GetQueryParameter(GLenum pname) const86 Maybe<double> WebGLQuery::GetQueryParameter(GLenum pname) const {
87 switch (pname) {
88 case LOCAL_GL_QUERY_RESULT_AVAILABLE:
89 case LOCAL_GL_QUERY_RESULT:
90 break;
91
92 default:
93 mContext->ErrorInvalidEnumInfo("pname", pname);
94 return Nothing();
95 }
96
97 if (!mTarget) {
98 mContext->ErrorInvalidOperation("Query has never been active.");
99 return Nothing();
100 }
101
102 if (mActiveSlot) {
103 mContext->ErrorInvalidOperation("Query is still active.");
104 return Nothing();
105 }
106
107 // End of validation
108 ////
109
110 // We must usually wait for an event loop before the query can be available.
111 const bool canBeAvailable =
112 (mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries());
113 if (!canBeAvailable) {
114 if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
115 return Some(false);
116 }
117 return Nothing();
118 }
119
120 const auto& gl = mContext->gl;
121
122 uint64_t val = 0;
123 switch (pname) {
124 case LOCAL_GL_QUERY_RESULT_AVAILABLE:
125 gl->fGetQueryObjectuiv(mGLName, pname, (GLuint*)&val);
126 return Some(static_cast<bool>(val));
127
128 case LOCAL_GL_QUERY_RESULT:
129 switch (mTarget) {
130 case LOCAL_GL_TIME_ELAPSED_EXT:
131 case LOCAL_GL_TIMESTAMP_EXT:
132 if (mContext->Has64BitTimestamps()) {
133 gl->fGetQueryObjectui64v(mGLName, pname, &val);
134 break;
135 }
136 [[fallthrough]];
137
138 default:
139 gl->fGetQueryObjectuiv(mGLName, LOCAL_GL_QUERY_RESULT, (GLuint*)&val);
140 break;
141 }
142
143 switch (mTarget) {
144 case LOCAL_GL_ANY_SAMPLES_PASSED:
145 case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
146 case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
147 case LOCAL_GL_TIME_ELAPSED_EXT:
148 case LOCAL_GL_TIMESTAMP_EXT:
149 return Some(val);
150 }
151 MOZ_CRASH("Bad `mTarget`.");
152
153 default:
154 MOZ_CRASH("Bad `pname`.");
155 }
156 }
157
QueryCounter()158 void WebGLQuery::QueryCounter() {
159 const GLenum target = LOCAL_GL_TIMESTAMP_EXT;
160 if (mTarget && target != mTarget) {
161 mContext->ErrorInvalidOperation("Queries cannot change targets.");
162 return;
163 }
164
165 mTarget = target;
166 mCanBeAvailable = false;
167
168 const auto& gl = mContext->gl;
169 gl->fQueryCounter(mGLName, mTarget);
170
171 const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
172 availRunnable->mQueries.push_back(this);
173 }
174
175 } // namespace mozilla
176