Bug 1155470 - Fix queries. r=jgilbert
authorDan Glastonbury <dan.glastonbury@gmail.com>
Fri, 17 Apr 2015 11:17:07 +1000
changeset 259329 f67a0b28268035b608766a7e6a69a0b4659d4dc0
parent 259327 9b75aac198d0480ed6171099d086d37da97f29ff
child 259330 2dfff5537a5da668630d91c5b7ea95b268bff3d8
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1155470
milestone40.0a1
Bug 1155470 - Fix queries. r=jgilbert es3fTransformFeedbackTests exposed problems with queries. Queries are needed to get the number of transformed primitives.
dom/canvas/WebGL1Context.cpp
dom/canvas/WebGL1Context.h
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextQueries.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLQuery.cpp
--- a/dom/canvas/WebGL1Context.cpp
+++ b/dom/canvas/WebGL1Context.cpp
@@ -26,16 +26,23 @@ WebGL1Context::~WebGL1Context()
 }
 
 JSObject*
 WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
 {
     return dom::WebGLRenderingContextBinding::Wrap(cx, this, aGivenProto);
 }
 
+bool
+WebGL1Context::ValidateQueryTarget(GLenum target, const char* info)
+{
+    // TODO: Implement this for EXT_disjoint_timer
+    return false;
+}
+
 } // namespace mozilla
 
 nsresult
 NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result)
 {
     mozilla::Telemetry::Accumulate(mozilla::Telemetry::CANVAS_WEBGL_USED, 1);
 
     nsIDOMWebGLRenderingContext* ctx = mozilla::WebGL1Context::Create();
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -30,15 +30,15 @@ public:
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
     virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override;
     virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
-    
+    virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
     virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_1_CONTEXT_H_
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -350,25 +350,27 @@ public:
     void BindVertexArray(WebGLVertexArrayObject* vertexArray);
 */
 
 private:
     WebGL2Context();
 
     JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) override;
 
+    void UpdateBoundQuery(GLenum target, WebGLQuery* query);
+
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
 
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
     virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override;
     virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
-
+    virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
     virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextQueries.cpp
+++ b/dom/canvas/WebGL2ContextQueries.cpp
@@ -2,18 +2,17 @@
 /* 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 "WebGL2Context.h"
 #include "GLContext.h"
 #include "WebGLQuery.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
+namespace mozilla {
 
 /*
  * We fake ANY_SAMPLES_PASSED and ANY_SAMPLES_PASSED_CONSERVATIVE with
  * SAMPLES_PASSED on desktop.
  *
  * OpenGL ES 3.0 spec 4.1.6:
  *     If the target of the query is ANY_SAMPLES_PASSED_CONSERVATIVE, an
  *     implementation may choose to use a less precise version of the test which
@@ -21,24 +20,24 @@ using namespace mozilla::dom;
  *     implementation-dependent cases.
  */
 
 static const char*
 GetQueryTargetEnumString(GLenum target)
 {
     switch (target)
     {
-        case LOCAL_GL_ANY_SAMPLES_PASSED:
-            return "ANY_SAMPLES_PASSED";
-        case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
-            return "ANY_SAMPLES_PASSED_CONSERVATIVE";
-        case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
-            return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
-        default:
-            break;
+    case LOCAL_GL_ANY_SAMPLES_PASSED:
+        return "ANY_SAMPLES_PASSED";
+    case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+        return "ANY_SAMPLES_PASSED_CONSERVATIVE";
+    case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+        return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
+    default:
+        break;
     }
 
     MOZ_ASSERT(false, "Unknown query `target`.");
     return "UNKNOWN_QUERY_TARGET";
 }
 
 static inline GLenum
 SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
@@ -51,29 +50,33 @@ SimulateOcclusionQueryTarget(const gl::G
         return target;
     } else if (gl->IsSupported(gl::GLFeature::occlusion_query2)) {
         return LOCAL_GL_ANY_SAMPLES_PASSED;
     }
 
     return LOCAL_GL_SAMPLES_PASSED;
 }
 
-WebGLRefPtr<WebGLQuery>*
-WebGLContext::GetQueryTargetSlot(GLenum target)
+WebGLRefPtr<WebGLQuery>&
+WebGLContext::GetQuerySlotByTarget(GLenum target)
 {
+    /* This function assumes that target has been validated for either
+     * WebGL1 or WebGL2.
+     */
     switch (target) {
-        case LOCAL_GL_ANY_SAMPLES_PASSED:
-        case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
-            return &mActiveOcclusionQuery;
+    case LOCAL_GL_ANY_SAMPLES_PASSED:
+    case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+        return mActiveOcclusionQuery;
 
-        case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
-            return &mActiveTransformFeedbackQuery;
+    case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+        return mActiveTransformFeedbackQuery;
+
+    default:
+        MOZ_CRASH("Should not get here.");
     }
-
-    return nullptr;
 }
 
 
 // -------------------------------------------------------------------------
 // Query Objects
 
 already_AddRefed<WebGLQuery>
 WebGL2Context::CreateQuery()
@@ -147,21 +150,18 @@ WebGL2Context::IsQuery(WebGLQuery* query
 }
 
 void
 WebGL2Context::BeginQuery(GLenum target, WebGLQuery* query)
 {
     if (IsContextLost())
         return;
 
-    WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
-    if (!targetSlot) {
-        ErrorInvalidEnum("beginQuery: unknown query target");
+    if (!ValidateQueryTarget(target, "beginQuery"))
         return;
-    }
 
     if (!query) {
         /* From GLES's EXT_occlusion_query_boolean:
          *     BeginQueryEXT sets the active query object name for the query
          *     type given by <target> to <id>. If BeginQueryEXT is called with
          *     an <id> of zero, if the active query object name for <target> is
          *     non-zero (for the targets ANY_SAMPLES_PASSED_EXT and
          *     ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the active query for
@@ -188,51 +188,50 @@ WebGL2Context::BeginQuery(GLenum target,
     if (query->HasEverBeenActive() &&
         query->mType != target)
     {
         ErrorInvalidOperation("beginQuery: Target doesn't match with the query"
                               " type.");
         return;
     }
 
-    if (*targetSlot) {
-        ErrorInvalidOperation("beginQuery: An other query already active.");
-        return;
-    }
+    WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
+    WebGLQuery* activeQuery = querySlot.get();
+    if (activeQuery)
+        return ErrorInvalidOperation("beginQuery: An other query already active.");
 
     if (!query->HasEverBeenActive())
         query->mType = target;
 
     MakeContextCurrent();
 
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
         gl->fBeginQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
                         query->mGLName);
     } else {
         gl->fBeginQuery(SimulateOcclusionQueryTarget(gl, target),
                         query->mGLName);
     }
 
-    *targetSlot = query;
+    UpdateBoundQuery(target, query);
 }
 
 void
 WebGL2Context::EndQuery(GLenum target)
 {
     if (IsContextLost())
         return;
 
-    WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
-    if (!targetSlot) {
-        ErrorInvalidEnum("endQuery: unknown query target");
+    if (!ValidateQueryTarget(target, "endQuery"))
         return;
-    }
 
-    if (!*targetSlot ||
-        target != (*targetSlot)->mType)
+    WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
+    WebGLQuery* activeQuery = querySlot.get();
+
+    if (!activeQuery || target != activeQuery->mType)
     {
         /* From GLES's EXT_occlusion_query_boolean:
          *     marks the end of the sequence of commands to be tracked for the
          *     query type given by <target>. The active query object for
          *     <target> is updated to indicate that query results are not
          *     available, and the active query object name for <target> is reset
          *     to zero. When the commands issued prior to EndQueryEXT have
          *     completed and a final query result is available, the query object
@@ -250,40 +249,39 @@ WebGL2Context::EndQuery(GLenum target)
     MakeContextCurrent();
 
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
         gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
     } else {
         gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
     }
 
-    *targetSlot = nullptr;
+    UpdateBoundQuery(target, nullptr);
 }
 
 already_AddRefed<WebGLQuery>
 WebGL2Context::GetQuery(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return nullptr;
 
-    WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target);
-    if (!targetSlot) {
-        ErrorInvalidEnum("getQuery: unknown query target");
+    if (!ValidateQueryTarget(target, "getQuery"))
         return nullptr;
-    }
 
     if (pname != LOCAL_GL_CURRENT_QUERY) {
         /* OpenGL ES 3.0 spec 6.1.7:
          *     pname must be CURRENT_QUERY.
          */
         ErrorInvalidEnum("getQuery: `pname` must be CURRENT_QUERY.");
         return nullptr;
     }
 
-    nsRefPtr<WebGLQuery> tmp = targetSlot->get();
+    WebGLRefPtr<WebGLQuery>& targetSlot = GetQuerySlotByTarget(target);
+
+    nsRefPtr<WebGLQuery> tmp = targetSlot.get();
     return tmp.forget();
 }
 
 void
 WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
                                  JS::MutableHandleValue retval)
 {
     retval.set(JS::NullValue());
@@ -348,8 +346,32 @@ WebGL2Context::GetQueryParameter(JSConte
         return;
 
     default:
         break;
     }
 
     ErrorInvalidEnum("getQueryObject: `pname` must be QUERY_RESULT{_AVAILABLE}.");
 }
+
+void
+WebGL2Context::UpdateBoundQuery(GLenum target, WebGLQuery* query)
+{
+    WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
+    querySlot = query;
+}
+
+bool
+WebGL2Context::ValidateQueryTarget(GLenum target, const char* info)
+{
+    switch (target) {
+    case LOCAL_GL_ANY_SAMPLES_PASSED:
+    case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+    case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+        return true;
+
+    default:
+        ErrorInvalidEnumInfo(info, target);
+        return false;
+    }
+}
+
+} // namespace mozilla
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -931,17 +931,17 @@ protected:
 
     WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
     WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
                                                            GLuint index);
 
 // -----------------------------------------------------------------------------
 // Queries (WebGL2ContextQueries.cpp)
 protected:
-    WebGLRefPtr<WebGLQuery>* GetQueryTargetSlot(GLenum target);
+    WebGLRefPtr<WebGLQuery>& GetQuerySlotByTarget(GLenum target);
 
     WebGLRefPtr<WebGLQuery> mActiveOcclusionQuery;
     WebGLRefPtr<WebGLQuery> mActiveTransformFeedbackQuery;
 
 // -----------------------------------------------------------------------------
 // State and State Requests (WebGLContextState.cpp)
 public:
     void Disable(GLenum cap);
@@ -1384,16 +1384,17 @@ private:
 private:
     // -------------------------------------------------------------------------
     // Context customization points
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
     virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) = 0;
     virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0;
+    virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
     virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
 
 protected:
     int32_t MaxTextureSizeForTarget(TexTarget target) const {
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize
                                                : mGLMaxCubeMapTextureSize;
     }
 
--- a/dom/canvas/WebGLQuery.cpp
+++ b/dom/canvas/WebGLQuery.cpp
@@ -35,20 +35,19 @@ WebGLQuery::Delete()
     mContext->MakeContextCurrent();
     mContext->gl->fDeleteQueries(1, &mGLName);
     LinkedListElement<WebGLQuery>::removeFrom(mContext->mQueries);
 }
 
 bool
 WebGLQuery::IsActive() const
 {
-    WebGLRefPtr<WebGLQuery>* targetSlot = mContext->GetQueryTargetSlot(mType);
+    WebGLRefPtr<WebGLQuery>& targetSlot = mContext->GetQuerySlotByTarget(mType);
 
-    MOZ_ASSERT(targetSlot, "unknown query object's type");
-    return targetSlot && *targetSlot == this;
+    return targetSlot.get() == this;
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLQuery)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLQuery, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLQuery, Release)
 
 } // namespace mozilla