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() { |