content/canvas/src/WebGLContextAsyncQueries.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 4; 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/. */
     6 #include "WebGLContext.h"
     7 #include "WebGLQuery.h"
     8 #include "GLContext.h"
    10 using namespace mozilla;
    12 /*
    13  * We fake ANY_SAMPLES_PASSED and ANY_SAMPLES_PASSED_CONSERVATIVE with
    14  * SAMPLES_PASSED on desktop.
    15  *
    16  * OpenGL ES 3.0 spec 4.1.6
    17  *  If the target of the query is ANY_SAMPLES_PASSED_CONSERVATIVE, an implementation
    18  *  may choose to use a less precise version of the test which can additionally set
    19  *  the samples-boolean state to TRUE in some other implementation-dependent cases.
    20  */
    22 static const char*
    23 GetQueryTargetEnumString(GLenum target)
    24 {
    25     switch (target)
    26     {
    27         case LOCAL_GL_ANY_SAMPLES_PASSED:
    28             return "ANY_SAMPLES_PASSED";
    29         case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
    30             return "ANY_SAMPLES_PASSED_CONSERVATIVE";
    31         case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
    32             return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
    33         default:
    34             break;
    35     }
    37     MOZ_ASSERT(false, "Unknown query `target`.");
    38     return "UNKNOWN_QUERY_TARGET";
    39 }
    41 static inline GLenum
    42 SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
    43 {
    44     MOZ_ASSERT(target == LOCAL_GL_ANY_SAMPLES_PASSED ||
    45                target == LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
    46                "unknown occlusion query target");
    48     if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) {
    49         return target;
    50     } else if (gl->IsSupported(gl::GLFeature::occlusion_query2)) {
    51         return LOCAL_GL_ANY_SAMPLES_PASSED;
    52     }
    54     return LOCAL_GL_SAMPLES_PASSED;
    55 }
    57 already_AddRefed<WebGLQuery>
    58 WebGLContext::CreateQuery()
    59 {
    60     if (IsContextLost())
    61         return nullptr;
    63     if (mActiveOcclusionQuery && !gl->IsGLES()) {
    64         /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
    65          * Calling either GenQueriesARB or DeleteQueriesARB while any query of
    66          * any target is active causes an INVALID_OPERATION error to be
    67          * generated.
    68          */
    69         GenerateWarning("createQuery: the WebGL 2 prototype might generate INVALID_OPERATION"
    70                         "when creating a query object while one other is active.");
    71         /*
    72          * We *need* to lock webgl2 to GL>=3.0 on desktop, but we don't have a good
    73          * mechanism to do this yet. See bug 898404.
    74          */
    75     }
    77     nsRefPtr<WebGLQuery> globj = new WebGLQuery(this);
    79     return globj.forget();
    80 }
    82 void
    83 WebGLContext::DeleteQuery(WebGLQuery *query)
    84 {
    85     if (IsContextLost())
    86         return;
    88     if (!query)
    89         return;
    91     if (query->IsDeleted())
    92         return;
    94     if (query->IsActive()) {
    95         EndQuery(query->mType);
    96     }
    98     if (mActiveOcclusionQuery && !gl->IsGLES()) {
    99         /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
   100          * Calling either GenQueriesARB or DeleteQueriesARB while any query of
   101          * any target is active causes an INVALID_OPERATION error to be
   102          * generated.
   103          */
   104         GenerateWarning("deleteQuery: the WebGL 2 prototype might generate INVALID_OPERATION"
   105                         "when deleting a query object while one other is active.");
   106     }
   108     query->RequestDelete();
   109 }
   111 void
   112 WebGLContext::BeginQuery(GLenum target, WebGLQuery *query)
   113 {
   114     if (IsContextLost())
   115         return;
   117     WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "beginQuery");
   118     if (!targetSlot) {
   119         return;
   120     }
   122     if (!query) {
   123         /* SPECS BeginQuery.1
   124          * http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
   125          * BeginQueryEXT sets the active query object name for the query type given
   126          * by <target> to <id>. If BeginQueryEXT is called with an <id> of zero, if
   127          * the active query object name for <target> is non-zero (for the targets
   128          * ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the
   129          * active query for either target is non-zero), if <id> is the name of an
   130          * existing query object whose type does not match <target>, or if <id> is the
   131          * active query object name for any query type, the error INVALID_OPERATION is
   132          * generated.
   133          */
   134         ErrorInvalidOperation("beginQuery: query should not be null");
   135         return;
   136     }
   138     if (query->IsDeleted()) {
   139         /* http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
   140          * BeginQueryEXT fails and an INVALID_OPERATION error is generated if <id>
   141          * is not a name returned from a previous call to GenQueriesEXT, or if such
   142          * a name has since been deleted with DeleteQueriesEXT.
   143          */
   144         ErrorInvalidOperation("beginQuery: query has been deleted");
   145         return;
   146     }
   148     if (query->HasEverBeenActive() &&
   149         query->mType != target)
   150     {
   151         /*
   152          * See SPECS BeginQuery.1
   153          */
   154         ErrorInvalidOperation("beginQuery: target doesn't match with the query type");
   155         return;
   156     }
   158     if (*targetSlot) {
   159         /*
   160          * See SPECS BeginQuery.1
   161          */
   162         ErrorInvalidOperation("beginQuery: an other query already active");
   163         return;
   164     }
   166     if (!query->HasEverBeenActive()) {
   167         query->mType = target;
   168     }
   170     MakeContextCurrent();
   172     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
   173         gl->fBeginQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->mGLName);
   174     } else {
   175         gl->fBeginQuery(SimulateOcclusionQueryTarget(gl, target), query->mGLName);
   176     }
   178     *targetSlot = query;
   179 }
   181 void
   182 WebGLContext::EndQuery(GLenum target)
   183 {
   184     if (IsContextLost())
   185         return;
   187     WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "endQuery");
   188     if (!targetSlot) {
   189         return;
   190     }
   192     if (!*targetSlot ||
   193         target != (*targetSlot)->mType)
   194     {
   195         /* http://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt
   196          * marks the end of the sequence of commands to be tracked for the query type
   197          * given by <target>. The active query object for <target> is updated to
   198          * indicate that query results are not available, and the active query object
   199          * name for <target> is reset to zero. When the commands issued prior to
   200          * EndQueryEXT have completed and a final query result is available, the
   201          * query object active when EndQueryEXT is called is updated by the GL. The
   202          * query object is updated to indicate that the query results are available
   203          * and to contain the query result. If the active query object name for
   204          * <target> is zero when EndQueryEXT is called, the error INVALID_OPERATION
   205          * is generated.
   206          */
   207         ErrorInvalidOperation("endQuery: There is no active query of type %s.",
   208                               GetQueryTargetEnumString(target));
   209         return;
   210     }
   212     MakeContextCurrent();
   214     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
   215         gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
   216     } else {
   217         gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
   218     }
   220     *targetSlot = nullptr;
   221 }
   223 bool
   224 WebGLContext::IsQuery(WebGLQuery *query)
   225 {
   226     if (IsContextLost())
   227         return false;
   229     if (!query)
   230         return false;
   232     return ValidateObjectAllowDeleted("isQuery", query) &&
   233            !query->IsDeleted() &&
   234            query->HasEverBeenActive();
   235 }
   237 already_AddRefed<WebGLQuery>
   238 WebGLContext::GetQuery(GLenum target, GLenum pname)
   239 {
   240     if (IsContextLost())
   241         return nullptr;
   243     WebGLRefPtr<WebGLQuery>* targetSlot = GetQueryTargetSlot(target, "getQuery");
   244     if (!targetSlot) {
   245         return nullptr;
   246     }
   248     if (pname != LOCAL_GL_CURRENT_QUERY) {
   249         /* OpenGL ES 3.0 spec 6.1.7
   250          *  pname must be CURRENT_QUERY.
   251          */
   252         ErrorInvalidEnum("getQuery: pname must be CURRENT_QUERY");
   253         return nullptr;
   254     }
   256     nsRefPtr<WebGLQuery> tmp = targetSlot->get();
   257     return tmp.forget();
   258 }
   260 JS::Value
   261 WebGLContext::GetQueryObject(JSContext* cx, WebGLQuery *query, GLenum pname)
   262 {
   263     if (IsContextLost())
   264         return JS::NullValue();
   266     if (!query) {
   267         /* OpenGL ES 3.0 spec 6.1.7 (spec getQueryObject 1)
   268          *  If id is not the name of a query object, or if the query object named by id is
   269          *  currently active, then an INVALID_OPERATION error is generated. pname must be
   270          *  QUERY_RESULT or QUERY_RESULT_AVAILABLE.
   271          */
   272         ErrorInvalidOperation("getQueryObject: query should not be null");
   273         return JS::NullValue();
   274     }
   276     if (query->IsDeleted()) {
   277         // See (spec getQueryObject 1)
   278         ErrorInvalidOperation("getQueryObject: query has been deleted");
   279         return JS::NullValue();
   280     }
   282     if (query->IsActive()) {
   283         // See (spec getQueryObject 1)
   284         ErrorInvalidOperation("getQueryObject: query is active");
   285         return JS::NullValue();
   286     }
   288     if (!query->HasEverBeenActive()) {
   289         /* See (spec getQueryObject 1)
   290          *  If this instance of WebGLQuery has never been active before, that mean that
   291          *  query->mGLName is not a query object yet.
   292          */
   293         ErrorInvalidOperation("getQueryObject: query has never been active");
   294         return JS::NullValue();
   295     }
   297     switch (pname)
   298     {
   299         case LOCAL_GL_QUERY_RESULT_AVAILABLE:
   300         {
   301             GLuint returned = 0;
   303             MakeContextCurrent();
   304             gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
   306             return JS::BooleanValue(returned != 0);
   307         }
   309         case LOCAL_GL_QUERY_RESULT:
   310         {
   311             GLuint returned = 0;
   313             MakeContextCurrent();
   314             gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT, &returned);
   316             if (query->mType == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
   317                 return JS::NumberValue(uint32_t(returned));
   318             }
   320             /*
   321              * test (returned != 0) is important because ARB_occlusion_query on desktop drivers
   322              * return the number of samples drawed when the OpenGL ES extension
   323              * ARB_occlusion_query_boolean return only a boolean if a sample has been drawed.
   324              */
   325             return JS::BooleanValue(returned != 0);
   326         }
   328         default:
   329             break;
   330     }
   332     ErrorInvalidEnum("getQueryObject: pname must be QUERY_RESULT{_AVAILABLE}");
   333     return JS::NullValue();
   334 }
   336 WebGLRefPtr<WebGLQuery>*
   337 WebGLContext::GetQueryTargetSlot(GLenum target, const char* infos)
   338 {
   339     switch (target) {
   340         case LOCAL_GL_ANY_SAMPLES_PASSED:
   341         case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
   342             return &mActiveOcclusionQuery;
   343         case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
   344             return &mActiveTransformFeedbackQuery;
   345     }
   347     ErrorInvalidEnum("%s: unknown query target", infos);
   348     return nullptr;
   349 }

mercurial