Bug 1442502 - Require event loop roundtrip for WebGLSync. - r=kvark
MozReview-Commit-ID: 6h6j2LvJdXm
--- a/dom/canvas/WebGL2ContextSync.cpp
+++ b/dom/canvas/WebGL2ContextSync.cpp
@@ -25,16 +25,20 @@ WebGL2Context::FenceSync(GLenum conditio
}
if (flags != 0) {
ErrorInvalidValue("fenceSync: flags must be 0");
return nullptr;
}
RefPtr<WebGLSync> globj = new WebGLSync(this, condition, flags);
+
+ const auto& availRunnable = EnsureAvailabilityRunnable();
+ availRunnable->mSyncs.push_back(globj);
+
return globj.forget();
}
bool
WebGL2Context::IsSync(const WebGLSync* sync)
{
if (!ValidateIsObject("isSync", sync))
return false;
@@ -67,16 +71,27 @@ WebGL2Context::ClientWaitSync(const WebG
}
if (timeout > kMaxClientWaitSyncTimeoutNS) {
ErrorInvalidOperation("%s: `timeout` must not exceed %s nanoseconds.", funcName,
"MAX_CLIENT_WAIT_TIMEOUT_WEBGL");
return LOCAL_GL_WAIT_FAILED;
}
+ const bool canBeAvailable = (sync.mCanBeAvailable ||
+ gfxPrefs::WebGLImmediateQueries());
+ if (!canBeAvailable) {
+ if (timeout) {
+ GenerateWarning("%s: Sync object not yet queryable. Please wait for the event"
+ " loop.",
+ funcName);
+ }
+ return LOCAL_GL_WAIT_FAILED;
+ }
+
const auto ret = gl->fClientWaitSync(sync.mGLName, flags, timeout);
if (ret == LOCAL_GL_CONDITION_SATISFIED ||
ret == LOCAL_GL_ALREADY_SIGNALED)
{
sync.MarkSignaled();
}
@@ -115,16 +130,23 @@ WebGL2Context::GetSyncParameter(JSContex
if (IsContextLost())
return;
if (!ValidateObject(funcName, sync))
return;
////
+ const bool canBeAvailable = (sync.mCanBeAvailable ||
+ gfxPrefs::WebGLImmediateQueries());
+ if (!canBeAvailable && pname == LOCAL_GL_SYNC_STATUS) {
+ retval.set(JS::Int32Value(LOCAL_GL_UNSIGNALED));
+ return;
+ }
+
GLint result = 0;
switch (pname) {
case LOCAL_GL_OBJECT_TYPE:
case LOCAL_GL_SYNC_STATUS:
case LOCAL_GL_SYNC_CONDITION:
case LOCAL_GL_SYNC_FLAGS:
gl->fGetSynciv(sync.mGLName, pname, 1, nullptr, &result);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -227,16 +227,20 @@ WebGLContext::DestroyResourcesAndContext
mDefaultTransformFeedback = nullptr;
mQuerySlot_SamplesPassed = nullptr;
mQuerySlot_TFPrimsWritten = nullptr;
mQuerySlot_TimeElapsed = nullptr;
mIndexedUniformBufferBindings.clear();
+ if (mAvailabilityRunnable) {
+ mAvailabilityRunnable->Run();
+ }
+
//////
ClearLinkedList(mBuffers);
ClearLinkedList(mFramebuffers);
ClearLinkedList(mPrograms);
ClearLinkedList(mQueries);
ClearLinkedList(mRenderbuffers);
ClearLinkedList(mSamplers);
@@ -2446,16 +2450,64 @@ WebGLContext::UpdateMaxDrawBuffers()
mGLMaxDrawBuffers = gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_DRAW_BUFFERS);
// WEBGL_draw_buffers:
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
mGLMaxDrawBuffers = std::min(mGLMaxDrawBuffers, mGLMaxColorAttachments);
}
+// --
+
+webgl::AvailabilityRunnable*
+WebGLContext::EnsureAvailabilityRunnable()
+{
+ if (!mAvailabilityRunnable) {
+ RefPtr<webgl::AvailabilityRunnable> runnable = new webgl::AvailabilityRunnable(this);
+
+ nsIDocument* document = GetOwnerDoc();
+ if (document) {
+ document->Dispatch(TaskCategory::Other, runnable.forget());
+ } else {
+ NS_DispatchToCurrentThread(runnable.forget());
+ }
+ }
+ return mAvailabilityRunnable;
+}
+
+webgl::AvailabilityRunnable::AvailabilityRunnable(WebGLContext* const webgl)
+ : Runnable("webgl::AvailabilityRunnable")
+ , mWebGL(webgl)
+{
+ mWebGL->mAvailabilityRunnable = this;
+}
+
+webgl::AvailabilityRunnable::~AvailabilityRunnable()
+{
+ MOZ_ASSERT(mQueries.empty());
+ MOZ_ASSERT(mSyncs.empty());
+}
+
+nsresult
+webgl::AvailabilityRunnable::Run()
+{
+ for (const auto& cur : mQueries) {
+ cur->mCanBeAvailable = true;
+ }
+ mQueries.clear();
+
+ for (const auto& cur : mSyncs) {
+ cur->mCanBeAvailable = true;
+ }
+ mSyncs.clear();
+
+ mWebGL->mAvailabilityRunnable = nullptr;
+ return NS_OK;
+}
+
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,
const char* name, uint32_t flags)
{
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -98,16 +98,17 @@ class SourceSurface;
class VRLayerChild;
} // namespace gfx
namespace gl {
class MozFramebuffer;
} // namespace gl
namespace webgl {
+class AvailabilityRunnable;
struct LinkedProgramInfo;
class ShaderValidator;
class TexUnpackBlob;
struct UniformInfo;
struct UniformBlockInfo;
} // namespace webgl
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
@@ -265,16 +266,33 @@ struct TexImageSourceAdapter final : pub
}
TexImageSourceAdapter(const dom::Element* domElem, ErrorResult* const out_error) {
mDomElem = domElem;
mOut_error = out_error;
}
};
+// --
+
+namespace webgl {
+class AvailabilityRunnable final : public Runnable
+{
+public:
+ const RefPtr<WebGLContext> mWebGL; // Prevent CC
+ std::vector<RefPtr<WebGLQuery>> mQueries;
+ std::vector<RefPtr<WebGLSync>> mSyncs;
+
+ explicit AvailabilityRunnable(WebGLContext* webgl);
+ ~AvailabilityRunnable();
+
+ NS_IMETHOD Run() override;
+};
+} // namespace webgl
+
////////////////////////////////////////////////////////////////////////////////
class WebGLContext
: public nsICanvasRenderingContextInternal
, public nsSupportsWeakReference
, public WebGLContextUnchecked
, public nsWrapperCache
{
@@ -292,16 +310,17 @@ class WebGLContext
friend class WebGLExtensionCompressedTextureS3TC;
friend class WebGLExtensionCompressedTextureS3TC_SRGB;
friend class WebGLExtensionDepthTexture;
friend class WebGLExtensionDisjointTimerQuery;
friend class WebGLExtensionDrawBuffers;
friend class WebGLExtensionLoseContext;
friend class WebGLExtensionVertexArray;
friend class WebGLMemoryTracker;
+ friend class webgl::AvailabilityRunnable;
friend struct webgl::LinkedProgramInfo;
friend struct webgl::UniformBlockInfo;
enum {
UNPACK_FLIP_Y_WEBGL = 0x9240,
UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
// We throw InvalidOperation in TexImage if we fail to use GPU fast-path
// for texture copy when it is set to true, only for debug purpose.
@@ -2045,16 +2064,22 @@ public:
virtual UniquePtr<webgl::FormatUsageAuthority>
CreateFormatUsage(gl::GLContext* gl) const = 0;
const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const;
void UpdateMaxDrawBuffers();
+ // --
+private:
+ webgl::AvailabilityRunnable* mAvailabilityRunnable = nullptr;
+public:
+ webgl::AvailabilityRunnable* EnsureAvailabilityRunnable();
+
// Friend list
friend class ScopedCopyTexImageSource;
friend class ScopedResolveTexturesForDraw;
friend class ScopedUnpackReset;
friend class webgl::TexUnpackBlob;
friend class webgl::TexUnpackBytes;
friend class webgl::TexUnpackImage;
friend class webgl::TexUnpackSurface;
--- a/dom/canvas/WebGLQuery.cpp
+++ b/dom/canvas/WebGLQuery.cpp
@@ -8,74 +8,42 @@
#include "gfxPrefs.h"
#include "GLContext.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "nsContentUtils.h"
#include "WebGLContext.h"
namespace mozilla {
-class AvailableRunnable final : public Runnable
-{
- const RefPtr<WebGLQuery> mQuery;
-
-public:
- explicit AvailableRunnable(WebGLQuery* query)
- : Runnable("AvailableRunnable")
- , mQuery(query)
- {
- }
-
- NS_IMETHOD Run() override
- {
- mQuery->mCanBeAvailable = true;
- return NS_OK;
- }
-};
-
////
static GLuint
GenQuery(gl::GLContext* gl)
{
GLuint ret = 0;
gl->fGenQueries(1, &ret);
return ret;
}
WebGLQuery::WebGLQuery(WebGLContext* webgl)
: WebGLRefCountedObject(webgl)
, mGLName(GenQuery(mContext->gl))
, mTarget(0)
, mActiveSlot(nullptr)
- , mCanBeAvailable(false)
{
mContext->mQueries.insertBack(this);
}
void
WebGLQuery::Delete()
{
mContext->gl->fDeleteQueries(1, &mGLName);
LinkedListElement<WebGLQuery>::removeFrom(mContext->mQueries);
}
-static void
-DispatchAvailableRunnable(WebGLQuery* query)
-{
- RefPtr<AvailableRunnable> runnable = new AvailableRunnable(query);
-
- nsIDocument* document = query->mContext->GetOwnerDoc();
- if (document) {
- document->Dispatch(TaskCategory::Other, runnable.forget());
- return;
- }
- NS_DispatchToCurrentThread(runnable.forget());
-}
-
////
static GLenum
TargetForDriver(const gl::GLContext* gl, GLenum target)
{
switch (target) {
case LOCAL_GL_ANY_SAMPLES_PASSED:
case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
@@ -129,17 +97,18 @@ WebGLQuery::EndQuery()
const auto& gl = mContext->gl;
const auto driverTarget = TargetForDriver(gl, mTarget);
gl->fEndQuery(driverTarget);
////
- DispatchAvailableRunnable(this);
+ const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
+ availRunnable->mQueries.push_back(this);
}
void
WebGLQuery::GetQueryParameter(GLenum pname, JS::MutableHandleValue retval) const
{
const char funcName[] = "getQueryParameter";
switch (pname) {
@@ -252,17 +221,18 @@ WebGLQuery::QueryCounter(const char* fun
}
mTarget = target;
mCanBeAvailable = false;
const auto& gl = mContext->gl;
gl->fQueryCounter(mGLName, mTarget);
- DispatchAvailableRunnable(this);
+ const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
+ availRunnable->mQueries.push_back(this);
}
////
JSObject*
WebGLQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLQueryBinding::Wrap(cx, this, givenProto);
--- a/dom/canvas/WebGLQuery.h
+++ b/dom/canvas/WebGLQuery.h
@@ -8,32 +8,35 @@
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
#include "nsThreadUtils.h"
namespace mozilla {
+namespace webgl {
+class AvailabilityRunnable;
+} // namespace webgl
class WebGLQuery final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLQuery>
, public LinkedListElement<WebGLQuery>
{
- friend class AvailableRunnable;
+ friend class webgl::AvailabilityRunnable;
friend class WebGLRefCountedObject<WebGLQuery>;
public:
const GLuint mGLName;
private:
GLenum mTarget;
WebGLRefPtr<WebGLQuery>* mActiveSlot;
- bool mCanBeAvailable; // Track whether the event loop has spun
+ bool mCanBeAvailable = false; // Track whether the event loop has spun
////
public:
GLenum Target() const { return mTarget; }
bool IsActive() const { return bool(mActiveSlot); }
////
--- a/dom/canvas/WebGLSync.h
+++ b/dom/canvas/WebGLSync.h
@@ -6,26 +6,31 @@
#ifndef WEBGL_SYNC_H_
#define WEBGL_SYNC_H_
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
namespace mozilla {
+namespace webgl {
+class AvailabilityRunnable;
+} // namespace webgl
class WebGLSync final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLSync>
, public LinkedListElement<WebGLSync>
{
friend class WebGL2Context;
+ friend class webgl::AvailabilityRunnable;
const GLsync mGLName;
const uint64_t mFenceId;
+ bool mCanBeAvailable = false;
public:
WebGLSync(WebGLContext* webgl, GLenum condition, GLbitfield flags);
void Delete();
WebGLContext* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;