Index: tools/gpu/gl/GLTestContext.cpp |
diff --git a/tools/gpu/gl/GLTestContext.cpp b/tools/gpu/gl/GLTestContext.cpp |
index 68980922cdc4c986ef1c3fae325a2ec6dfd9a8bf..c42de1f915b28c2b4496ba348fa4a9ef2e594814 100644 |
--- a/tools/gpu/gl/GLTestContext.cpp |
+++ b/tools/gpu/gl/GLTestContext.cpp |
@@ -6,9 +6,12 @@ |
*/ |
#include "GLTestContext.h" |
+#include "SkGpuTimer.h" |
#include "gl/GrGLUtil.h" |
+#include <string> |
namespace sk_gpu_test { |
+ |
class GLTestContext::GLFenceSync : public SkGpuFenceSync { |
public: |
static GLFenceSync* CreateIfSupported(const GLTestContext*); |
@@ -20,9 +23,9 @@ public: |
private: |
GLFenceSync() {} |
- static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117; |
- static const GrGLenum GL_WAIT_FAILED = 0x911d; |
- static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001; |
+ constexpr static GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117; |
bsalomon
2016/09/30 18:37:16
I believe we more commonly use "static constexpr"
csmartdalton
2016/10/03 16:52:24
Done.
|
+ constexpr static GrGLenum GL_WAIT_FAILED = 0x911d; |
+ constexpr static GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001; |
typedef struct __GLsync *GLsync; |
@@ -37,42 +40,6 @@ private: |
typedef SkGpuFenceSync INHERITED; |
}; |
-GLTestContext::GLTestContext() : TestContext() {} |
- |
-GLTestContext::~GLTestContext() { |
- SkASSERT(nullptr == fGL.get()); |
-} |
- |
-void GLTestContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) { |
- SkASSERT(!fGL.get()); |
- fGL.reset(gl); |
- fFenceSync = fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this); |
-} |
- |
-void GLTestContext::teardown() { |
- fGL.reset(nullptr); |
- INHERITED::teardown(); |
-} |
- |
-void GLTestContext::testAbandon() { |
- INHERITED::testAbandon(); |
- if (fGL) { |
- fGL->abandon(); |
- } |
-} |
- |
-void GLTestContext::submit() { |
- if (fGL) { |
- GR_GL_CALL(fGL.get(), Flush()); |
- } |
-} |
- |
-void GLTestContext::finish() { |
- if (fGL) { |
- GR_GL_CALL(fGL.get(), Finish()); |
- } |
-} |
- |
GLTestContext::GLFenceSync* GLTestContext::GLFenceSync::CreateIfSupported(const GLTestContext* ctx) { |
SkAutoTDelete<GLFenceSync> ret(new GLFenceSync); |
@@ -122,6 +89,188 @@ void GLTestContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const { |
fGLDeleteSync(glsync); |
} |
+//////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+class GLGpuTimer : public SkGpuTimer { |
+public: |
+ static GLGpuTimer* CreateIfSupported(const GLTestContext*); |
+ |
+ QueryStatus checkQueryStatus(SkPlatformGpuTimerQuery) override; |
+ std::chrono::nanoseconds getTimeElapsed(SkPlatformGpuTimerQuery) override; |
+ void deleteQuery(SkPlatformGpuTimerQuery) override; |
+ |
+private: |
+ GLGpuTimer(bool disjointSupport, const GLTestContext*, const char* ext = ""); |
+ |
+ template<typename Proc> void loadProc(Proc GLGpuTimer::* proc, const GLTestContext* ctx, |
+ const std::string& name, const std::string& ext = "") { |
+ const std::string& fullname = name + ext; |
+ this->*proc = reinterpret_cast<Proc>(ctx->onPlatformGetProcAddress(fullname.c_str())); |
+ } |
+ |
+ bool validate() const { |
+ return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery |
+ && fGLQueryCounter && fGLGetQueryiv && fGLGetQueryObjectiv && fGLGetQueryObjectui64v; |
+ } |
+ |
+ SkPlatformGpuTimerQuery onQueueTimerStart() const override; |
+ void onQueueTimerStop(SkPlatformGpuTimerQuery) const override; |
+ |
+ constexpr static GrGLenum GL_QUERY_COUNTER_BITS = 0x8864; |
+ constexpr static GrGLenum GL_CURRENT_QUERY = 0x8865; |
+ constexpr static GrGLenum GL_QUERY_RESULT = 0x8866; |
+ constexpr static GrGLenum GL_QUERY_RESULT_AVAILABLE = 0x8867; |
+ constexpr static GrGLenum GL_TIME_ELAPSED = 0x88bf; |
+ constexpr static GrGLenum GL_TIMESTAMP = 0x8e28; |
+ constexpr static 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* GLQueryCounterProc) (GrGLuint, GrGLenum); |
+ typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryivProc) (GrGLenum, GrGLenum, GrGLint *); |
+ typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectivProc) (GrGLuint, GrGLenum, GrGLint*); |
+ typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*); |
+ |
+ GLGetIntegervProc fGLGetIntegerv; |
+ GLGenQueriesProc fGLGenQueries; |
+ GLDeleteQueriesProc fGLDeleteQueries; |
+ GLBeginQueryProc fGLBeginQuery; |
+ GLEndQueryProc fGLEndQuery; |
+ GLQueryCounterProc fGLQueryCounter; |
+ GLGetQueryivProc fGLGetQueryiv; |
+ GLGetQueryObjectivProc fGLGetQueryObjectiv; |
+ GLGetQueryObjectui64vProc fGLGetQueryObjectui64v; |
+}; |
+ |
+GLGpuTimer* GLGpuTimer::CreateIfSupported(const 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 GLTestContext* ctx, const char* ext) |
+ : SkGpuTimer(disjointSupport) { |
+ this->loadProc(&GLGpuTimer::fGLGetIntegerv, ctx, "glGetIntegerv"); |
+ this->loadProc(&GLGpuTimer::fGLGenQueries, ctx, "glGenQueries", ext); |
+ this->loadProc(&GLGpuTimer::fGLDeleteQueries, ctx, "glDeleteQueries", ext); |
+ this->loadProc(&GLGpuTimer::fGLBeginQuery, ctx, "glBeginQuery", ext); |
+ this->loadProc(&GLGpuTimer::fGLEndQuery, ctx, "glEndQuery", ext); |
+ this->loadProc(&GLGpuTimer::fGLQueryCounter, ctx, "glQueryCounter", ext); |
+ this->loadProc(&GLGpuTimer::fGLGetQueryiv, ctx, "glGetQueryiv", ext); |
+ this->loadProc(&GLGpuTimer::fGLGetQueryObjectiv, ctx, "glGetQueryObjectiv", ext); |
+ this->loadProc(&GLGpuTimer::fGLGetQueryObjectui64v, ctx, "glGetQueryObjectui64v", ext); |
+} |
+ |
+SkPlatformGpuTimerQuery GLGpuTimer::onQueueTimerStart() const { |
+ GrGLuint queryID; |
+ fGLGenQueries(1, &queryID); |
+ if (!queryID) { |
+ return SK_InvalidGpuTimerQuery; |
+ } |
+ if (this->disjointSupport()) { |
+ // Clear the disjoint flag. |
+ GrGLint disjoint; |
+ fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); |
+ } |
+ fGLBeginQuery(GL_TIME_ELAPSED, queryID); |
+ return static_cast<SkPlatformGpuTimerQuery>(queryID); |
+} |
+ |
+void GLGpuTimer::onQueueTimerStop(SkPlatformGpuTimerQuery platformTimer) const { |
+ if (SK_InvalidGpuTimerQuery == platformTimer) { |
+ return; |
+ } |
+ fGLEndQuery(GL_TIME_ELAPSED); |
+} |
+ |
+SkGpuTimer::QueryStatus GLGpuTimer::checkQueryStatus(SkPlatformGpuTimerQuery platformTimer) { |
+ const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); |
+ if (!queryID) { |
+ return QueryStatus::kInvalid; |
+ } |
+ |
+ // Check if the timer has completed. We should really use the 32-bit version of glGetQueryObject |
+ // here, but it doesn't seem to work on Pixel C. |
+ GrGLuint64 available = 0; |
+ fGLGetQueryObjectui64v(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(SkPlatformGpuTimerQuery 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(SkPlatformGpuTimerQuery platformTimer) { |
+ const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); |
+ fGLDeleteQueries(1, &queryID); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+GLTestContext::GLTestContext() : TestContext() {} |
+ |
+GLTestContext::~GLTestContext() { |
+ SkASSERT(nullptr == fGL.get()); |
+} |
+ |
+void GLTestContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) { |
+ SkASSERT(!fGL.get()); |
+ fGL.reset(gl); |
+ fFenceSync = fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this); |
+ fGpuTimer = GLGpuTimer::CreateIfSupported(this); |
+} |
+ |
+void GLTestContext::teardown() { |
+ fGL.reset(nullptr); |
+ INHERITED::teardown(); |
+} |
+ |
+void GLTestContext::testAbandon() { |
+ INHERITED::testAbandon(); |
+ if (fGL) { |
+ fGL->abandon(); |
+ } |
+} |
+ |
+void GLTestContext::submit() { |
+ if (fGL) { |
+ GR_GL_CALL(fGL.get(), Flush()); |
+ } |
+} |
+ |
+void GLTestContext::finish() { |
+ if (fGL) { |
+ GR_GL_CALL(fGL.get(), Finish()); |
+ } |
+} |
+ |
GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat, |
GrGLenum externalFormat, GrGLenum externalType, |
GrGLvoid* data) { |
@@ -149,4 +298,5 @@ GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum in |
externalFormat, externalType, data)); |
return id; |
} |
+ |
} // namespace sk_gpu_test |