diff options
Diffstat (limited to 'dom/canvas/WebGLQuery.cpp')
-rw-r--r-- | dom/canvas/WebGLQuery.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/dom/canvas/WebGLQuery.cpp b/dom/canvas/WebGLQuery.cpp new file mode 100644 index 0000000000..5290d69a50 --- /dev/null +++ b/dom/canvas/WebGLQuery.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WebGLQuery.h" + +#include "GLContext.h" +#include "mozilla/dom/WebGL2RenderingContextBinding.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "nsContentUtils.h" +#include "WebGLContext.h" + +namespace mozilla { + +//// + +static GLuint GenQuery(gl::GLContext* gl) { + GLuint ret = 0; + gl->fGenQueries(1, &ret); + return ret; +} + +WebGLQuery::WebGLQuery(WebGLContext* webgl) + : WebGLContextBoundObject(webgl), + mGLName(GenQuery(mContext->gl)), + mTarget(0), + mActiveSlot(nullptr) {} + +WebGLQuery::~WebGLQuery() { + if (!mContext) return; + mContext->gl->fDeleteQueries(1, &mGLName); +} + +//// + +static GLenum TargetForDriver(const gl::GLContext* gl, GLenum target) { + switch (target) { + case LOCAL_GL_ANY_SAMPLES_PASSED: + case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + break; + + default: + return target; + } + + if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) return target; + + if (gl->IsSupported(gl::GLFeature::occlusion_query2)) + return LOCAL_GL_ANY_SAMPLES_PASSED; + + return LOCAL_GL_SAMPLES_PASSED; +} + +void WebGLQuery::BeginQuery(GLenum target, RefPtr<WebGLQuery>& slot) { + mTarget = target; + mActiveSlot = &slot; + *mActiveSlot = this; + + //// + + const auto& gl = mContext->gl; + + const auto driverTarget = TargetForDriver(gl, mTarget); + gl->fBeginQuery(driverTarget, mGLName); +} + +void WebGLQuery::EndQuery() { + *mActiveSlot = nullptr; + mActiveSlot = nullptr; + mCanBeAvailable = false; + + //// + + const auto& gl = mContext->gl; + + const auto driverTarget = TargetForDriver(gl, mTarget); + gl->fEndQuery(driverTarget); +} + +Maybe<double> WebGLQuery::GetQueryParameter(GLenum pname) const { + switch (pname) { + case LOCAL_GL_QUERY_RESULT_AVAILABLE: + case LOCAL_GL_QUERY_RESULT: + break; + + default: + mContext->ErrorInvalidEnumInfo("pname", pname); + return Nothing(); + } + + if (!mTarget) { + mContext->ErrorInvalidOperation("Query has never been active."); + return Nothing(); + } + + if (mActiveSlot) { + mContext->ErrorInvalidOperation("Query is still active."); + return Nothing(); + } + + // End of validation + //// + + const auto& gl = mContext->gl; + + uint64_t val = 0; + switch (pname) { + case LOCAL_GL_QUERY_RESULT_AVAILABLE: + gl->fGetQueryObjectuiv(mGLName, pname, (GLuint*)&val); + return Some(static_cast<bool>(val)); + + case LOCAL_GL_QUERY_RESULT: + switch (mTarget) { + case LOCAL_GL_TIME_ELAPSED_EXT: + case LOCAL_GL_TIMESTAMP_EXT: + if (mContext->Has64BitTimestamps()) { + gl->fGetQueryObjectui64v(mGLName, pname, &val); + break; + } + [[fallthrough]]; + + default: + gl->fGetQueryObjectuiv(mGLName, LOCAL_GL_QUERY_RESULT, (GLuint*)&val); + break; + } + + switch (mTarget) { + case LOCAL_GL_ANY_SAMPLES_PASSED: + case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + case LOCAL_GL_TIME_ELAPSED_EXT: + case LOCAL_GL_TIMESTAMP_EXT: + return Some(val); + } + MOZ_CRASH("Bad `mTarget`."); + + default: + MOZ_CRASH("Bad `pname`."); + } +} + +void WebGLQuery::QueryCounter() { + const GLenum target = LOCAL_GL_TIMESTAMP_EXT; + if (mTarget && target != mTarget) { + mContext->ErrorInvalidOperation("Queries cannot change targets."); + return; + } + + mTarget = target; + mCanBeAvailable = false; + + const auto& gl = mContext->gl; + gl->fQueryCounter(mGLName, mTarget); +} + +} // namespace mozilla |