| Index: tools/gpu/gl/GLTestContext.cpp | 
| diff --git a/tools/gpu/gl/GLTestContext.cpp b/tools/gpu/gl/GLTestContext.cpp | 
| index 1b077d5a022facd9d12755acc9bc4479fadf2702..20a99083810be034556d2fbddce92b357ca3dbbc 100644 | 
| --- a/tools/gpu/gl/GLTestContext.cpp | 
| +++ b/tools/gpu/gl/GLTestContext.cpp | 
| @@ -6,6 +6,8 @@ | 
| */ | 
|  | 
| #include "GLTestContext.h" | 
| + | 
| +#include "GpuTimer.h" | 
| #include "gl/GrGLUtil.h" | 
|  | 
| namespace { | 
| @@ -78,6 +80,135 @@ void GLFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const { | 
| fGLDeleteSync(glsync); | 
| } | 
|  | 
| +class GLGpuTimer : public sk_gpu_test::GpuTimer { | 
| +public: | 
| +    static GLGpuTimer* CreateIfSupported(const sk_gpu_test::GLTestContext*); | 
| + | 
| +    QueryStatus checkQueryStatus(sk_gpu_test::PlatformTimerQuery) override; | 
| +    std::chrono::nanoseconds getTimeElapsed(sk_gpu_test::PlatformTimerQuery) override; | 
| +    void deleteQuery(sk_gpu_test::PlatformTimerQuery) override; | 
| + | 
| +private: | 
| +    GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext*, const char* ext = ""); | 
| + | 
| +    bool validate() const; | 
| + | 
| +    sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override; | 
| +    void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override; | 
| + | 
| +    static constexpr GrGLenum GL_QUERY_RESULT            = 0x8866; | 
| +    static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE  = 0x8867; | 
| +    static constexpr GrGLenum GL_TIME_ELAPSED            = 0x88bf; | 
| +    static constexpr GrGLenum GL_GPU_DISJOINT            = 0x8fbb; | 
| + | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLDeleteQueriesProc) (GrGLsizei, const GrGLuint*); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLBeginQueryProc) (GrGLenum, GrGLuint); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLEndQueryProc) (GrGLenum); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectuivProc) (GrGLuint, GrGLenum, GrGLuint*); | 
| +    typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*); | 
| + | 
| +    GLGetIntegervProc           fGLGetIntegerv; | 
| +    GLGenQueriesProc            fGLGenQueries; | 
| +    GLDeleteQueriesProc         fGLDeleteQueries; | 
| +    GLBeginQueryProc            fGLBeginQuery; | 
| +    GLEndQueryProc              fGLEndQuery; | 
| +    GLGetQueryObjectuivProc     fGLGetQueryObjectuiv; | 
| +    GLGetQueryObjectui64vProc   fGLGetQueryObjectui64v; | 
| + | 
| + | 
| +    typedef sk_gpu_test::GpuTimer INHERITED; | 
| +}; | 
| + | 
| +GLGpuTimer* GLGpuTimer::CreateIfSupported(const sk_gpu_test::GLTestContext* ctx) { | 
| +    SkAutoTDelete<GLGpuTimer> ret; | 
| +    const GrGLInterface* gl = ctx->gl(); | 
| +    if (gl->fExtensions.has("GL_EXT_disjoint_timer_query")) { | 
| +        ret.reset(new GLGpuTimer(true, ctx, "EXT")); | 
| +    } else if (kGL_GrGLStandard == gl->fStandard && | 
| +               (GrGLGetVersion(gl) > GR_GL_VER(3,3) || gl->fExtensions.has("GL_ARB_timer_query"))) { | 
| +        ret.reset(new GLGpuTimer(false, ctx)); | 
| +    } else if (gl->fExtensions.has("GL_EXT_timer_query")) { | 
| +        ret.reset(new GLGpuTimer(false, ctx, "EXT")); | 
| +    } | 
| +    return ret && ret->validate() ? ret.release() : nullptr; | 
| +} | 
| + | 
| +GLGpuTimer::GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext* ctx, const char* ext) | 
| +    : INHERITED(disjointSupport) { | 
| +    ctx->getGLProcAddress(&fGLGetIntegerv, "glGetIntegerv"); | 
| +    ctx->getGLProcAddress(&fGLGenQueries, "glGenQueries", ext); | 
| +    ctx->getGLProcAddress(&fGLDeleteQueries, "glDeleteQueries", ext); | 
| +    ctx->getGLProcAddress(&fGLBeginQuery, "glBeginQuery", ext); | 
| +    ctx->getGLProcAddress(&fGLEndQuery, "glEndQuery", ext); | 
| +    ctx->getGLProcAddress(&fGLGetQueryObjectuiv, "glGetQueryObjectuiv", ext); | 
| +    ctx->getGLProcAddress(&fGLGetQueryObjectui64v, "glGetQueryObjectui64v", ext); | 
| +} | 
| + | 
| +bool GLGpuTimer::validate() const { | 
| +    return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery && | 
| +           fGLGetQueryObjectuiv && fGLGetQueryObjectui64v; | 
| +} | 
| + | 
| +sk_gpu_test::PlatformTimerQuery GLGpuTimer::onQueueTimerStart() const { | 
| +    GrGLuint queryID; | 
| +    fGLGenQueries(1, &queryID); | 
| +    if (!queryID) { | 
| +        return sk_gpu_test::kInvalidTimerQuery; | 
| +    } | 
| +    if (this->disjointSupport()) { | 
| +        // Clear the disjoint flag. | 
| +        GrGLint disjoint; | 
| +        fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); | 
| +    } | 
| +    fGLBeginQuery(GL_TIME_ELAPSED, queryID); | 
| +    return static_cast<sk_gpu_test::PlatformTimerQuery>(queryID); | 
| +} | 
| + | 
| +void GLGpuTimer::onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const { | 
| +    if (sk_gpu_test::kInvalidTimerQuery == platformTimer) { | 
| +        return; | 
| +    } | 
| +    fGLEndQuery(GL_TIME_ELAPSED); | 
| +} | 
| + | 
| +sk_gpu_test::GpuTimer::QueryStatus | 
| +GLGpuTimer::checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer) { | 
| +    const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); | 
| +    if (!queryID) { | 
| +        return QueryStatus::kInvalid; | 
| +    } | 
| +    GrGLuint available = 0; | 
| +    fGLGetQueryObjectuiv(queryID, GL_QUERY_RESULT_AVAILABLE, &available); | 
| +    if (!available) { | 
| +        return QueryStatus::kPending; | 
| +    } | 
| +    if (this->disjointSupport()) { | 
| +        GrGLint disjoint = 1; | 
| +        fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); | 
| +        if (disjoint) { | 
| +            return QueryStatus::kDisjoint; | 
| +        } | 
| +    } | 
| +    return QueryStatus::kAccurate; | 
| +} | 
| + | 
| +std::chrono::nanoseconds GLGpuTimer::getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer) { | 
| +    SkASSERT(this->checkQueryStatus(platformTimer) >= QueryStatus::kDisjoint); | 
| +    const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); | 
| +    GrGLuint64 nanoseconds; | 
| +    fGLGetQueryObjectui64v(queryID, GL_QUERY_RESULT, &nanoseconds); | 
| +    return std::chrono::nanoseconds(nanoseconds); | 
| +} | 
| + | 
| +void GLGpuTimer::deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer) { | 
| +    const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); | 
| +    fGLDeleteQueries(1, &queryID); | 
| +} | 
| + | 
| +GR_STATIC_ASSERT(sizeof(GrGLuint) <= sizeof(sk_gpu_test::PlatformTimerQuery)); | 
| + | 
| }  // anonymous namespace | 
|  | 
| namespace sk_gpu_test { | 
| @@ -92,6 +223,7 @@ void GLTestContext::init(const GrGLInterface* gl, FenceSync* fenceSync) { | 
| SkASSERT(!fGL.get()); | 
| fGL.reset(gl); | 
| fFenceSync = fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this); | 
| +    fGpuTimer = GLGpuTimer::CreateIfSupported(this); | 
| } | 
|  | 
| void GLTestContext::teardown() { | 
|  |