Edit

kc3-lang/angle/src/libANGLE/renderer/gl/QueryGL.cpp

Branch :

  • Show log

    Commit

  • Author : Ian Ewell
    Date : 2016-02-04 10:37:32
    Hash : 292f005f
    Message : Fix context virtualization for timer queries In the current implementation of query virtualization, queries are paused/resumed during draw calls. Timer queries however are affected by every OpenGL call, so virtualization and context switches for timer queries must happen every time there is a context switch. Thus the logic for context-switching queries was moved to a new function in the GL state manager that is called everytime a makeCurrent call on the context is made. Since queries may be made after a context is made current, the state manager needs to keep track of any new queries that are started in a context, so an additional delegate function was added to the state manager that is called every time a glBeginQuery() call is made that adds the query object to a set. All the queries in that set are paused when a context switch is made and the queries in the new context are then loaded and resumed. BUG=angleproject:1307 Change-Id: I4e596d83739274cb2e14152a39e86e0e51b0f95c Reviewed-on: https://chromium-review.googlesource.com/325811 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Ian Ewell <ewell@google.com>

  • src/libANGLE/renderer/gl/QueryGL.cpp
  • //
    // Copyright 2015 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // QueryGL.cpp: Implements the class methods for QueryGL.
    
    #include "libANGLE/renderer/gl/QueryGL.h"
    
    #include "common/debug.h"
    #include "libANGLE/renderer/gl/FunctionsGL.h"
    #include "libANGLE/renderer/gl/StateManagerGL.h"
    
    namespace
    {
    
    GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResult)
    {
        switch (type)
        {
            case GL_ANY_SAMPLES_PASSED:
            case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
                return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
    
            case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
                return currentResult + newResult;
    
            case GL_TIME_ELAPSED:
                return currentResult + newResult;
    
            case GL_TIMESTAMP:
                return newResult;
    
            default:
                UNREACHABLE();
                return 0;
        }
    }
    
    }  // anonymous namespace
    
    namespace rx
    {
    
    QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager)
        : QueryImpl(type),
          mType(type),
          mFunctions(functions),
          mStateManager(stateManager),
          mActiveQuery(0),
          mPendingQueries(),
          mResultSum(0)
    {
    }
    
    QueryGL::~QueryGL()
    {
        mStateManager->deleteQuery(mActiveQuery);
        mStateManager->onDeleteQueryObject(this);
        while (!mPendingQueries.empty())
        {
            mStateManager->deleteQuery(mPendingQueries.front());
            mPendingQueries.pop_front();
        }
    }
    
    gl::Error QueryGL::begin()
    {
        mResultSum = 0;
        mStateManager->onBeginQuery(this);
        return resume();
    }
    
    gl::Error QueryGL::end()
    {
        return pause();
    }
    
    gl::Error QueryGL::queryCounter()
    {
        ASSERT(mType == GL_TIMESTAMP);
    
        // Directly create a query for the timestamp and add it to the pending query queue, as timestamp
        // queries do not have the traditional begin/end block and never need to be paused/resumed
        GLuint query;
        mFunctions->genQueries(1, &query);
        mFunctions->queryCounter(query, GL_TIMESTAMP);
        mPendingQueries.push_back(query);
    
        return gl::Error(GL_NO_ERROR);
    }
    
    template <typename T>
    gl::Error QueryGL::getResultBase(T *params)
    {
        ASSERT(mActiveQuery == 0);
    
        gl::Error error = flush(true);
        if (error.isError())
        {
            return error;
        }
    
        ASSERT(mPendingQueries.empty());
        *params = static_cast<T>(mResultSum);
    
        return gl::Error(GL_NO_ERROR);
    }
    
    gl::Error QueryGL::getResult(GLint *params)
    {
        return getResultBase(params);
    }
    
    gl::Error QueryGL::getResult(GLuint *params)
    {
        return getResultBase(params);
    }
    
    gl::Error QueryGL::getResult(GLint64 *params)
    {
        return getResultBase(params);
    }
    
    gl::Error QueryGL::getResult(GLuint64 *params)
    {
        return getResultBase(params);
    }
    
    gl::Error QueryGL::isResultAvailable(bool *available)
    {
        ASSERT(mActiveQuery == 0);
    
        gl::Error error = flush(false);
        if (error.isError())
        {
            return error;
        }
    
        *available = mPendingQueries.empty();
        return gl::Error(GL_NO_ERROR);
    }
    
    gl::Error QueryGL::pause()
    {
        if (mActiveQuery != 0)
        {
            mStateManager->endQuery(mType, mActiveQuery);
    
            mPendingQueries.push_back(mActiveQuery);
            mActiveQuery = 0;
        }
    
        // Flush to make sure the pending queries don't add up too much.
        gl::Error error = flush(false);
        if (error.isError())
        {
            return error;
        }
    
        return gl::Error(GL_NO_ERROR);
    }
    
    gl::Error QueryGL::resume()
    {
        if (mActiveQuery == 0)
        {
            // Flush to make sure the pending queries don't add up too much.
            gl::Error error = flush(false);
            if (error.isError())
            {
                return error;
            }
    
            mFunctions->genQueries(1, &mActiveQuery);
            mStateManager->beginQuery(mType, mActiveQuery);
        }
    
        return gl::Error(GL_NO_ERROR);
    }
    
    gl::Error QueryGL::flush(bool force)
    {
        while (!mPendingQueries.empty())
        {
            GLuint id = mPendingQueries.front();
            if (!force)
            {
                GLuint resultAvailable = 0;
                mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
                if (resultAvailable == GL_FALSE)
                {
                    return gl::Error(GL_NO_ERROR);
                }
            }
    
            // Even though getQueryObjectui64v was introduced for timer queries, there is nothing in the
            // standard that says that it doesn't work for any other queries. It also passes on all the
            // trybots, so we use it if it is available
            if (mFunctions->getQueryObjectui64v != nullptr)
            {
                GLuint64 result = 0;
                mFunctions->getQueryObjectui64v(id, GL_QUERY_RESULT, &result);
                mResultSum = MergeQueryResults(mType, mResultSum, result);
            }
            else
            {
                GLuint result = 0;
                mFunctions->getQueryObjectuiv(id, GL_QUERY_RESULT, &result);
                mResultSum = MergeQueryResults(mType, mResultSum, static_cast<GLuint64>(result));
            }
    
            mStateManager->deleteQuery(id);
    
            mPendingQueries.pop_front();
        }
    
        return gl::Error(GL_NO_ERROR);
    }
    
    }