1/* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "tools/gpu/gl/GLTestContext.h" 9 10#include "include/gpu/GrDirectContext.h" 11#include "src/gpu/gl/GrGLUtil.h" 12#include "tools/gpu/GpuTimer.h" 13 14namespace { 15 16class GLGpuTimer : public sk_gpu_test::GpuTimer { 17public: 18 static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*); 19 20 QueryStatus checkQueryStatus(sk_gpu_test::PlatformTimerQuery) override; 21 std::chrono::nanoseconds getTimeElapsed(sk_gpu_test::PlatformTimerQuery) override; 22 void deleteQuery(sk_gpu_test::PlatformTimerQuery) override; 23 24private: 25#ifdef SK_GL 26 GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext*, const char* ext = ""); 27 bool validate() const; 28#endif 29 30 sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override; 31 void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override; 32 33 inline static constexpr GrGLenum GL_QUERY_RESULT = 0x8866; 34 inline static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE = 0x8867; 35 inline static constexpr GrGLenum GL_TIME_ELAPSED = 0x88bf; 36 inline static constexpr GrGLenum GL_GPU_DISJOINT = 0x8fbb; 37 38 typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*); 39 typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*); 40 typedef void (GR_GL_FUNCTION_TYPE* GLDeleteQueriesProc) (GrGLsizei, const GrGLuint*); 41 typedef void (GR_GL_FUNCTION_TYPE* GLBeginQueryProc) (GrGLenum, GrGLuint); 42 typedef void (GR_GL_FUNCTION_TYPE* GLEndQueryProc) (GrGLenum); 43 typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectuivProc) (GrGLuint, GrGLenum, GrGLuint*); 44 typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*); 45 46 GLGetIntegervProc fGLGetIntegerv; 47 GLGenQueriesProc fGLGenQueries; 48 GLDeleteQueriesProc fGLDeleteQueries; 49 GLBeginQueryProc fGLBeginQuery; 50 GLEndQueryProc fGLEndQuery; 51 GLGetQueryObjectuivProc fGLGetQueryObjectuiv; 52 GLGetQueryObjectui64vProc fGLGetQueryObjectui64v; 53 54 55 using INHERITED = sk_gpu_test::GpuTimer; 56}; 57 58std::unique_ptr<GLGpuTimer> GLGpuTimer::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) { 59#ifdef SK_GL 60 std::unique_ptr<GLGpuTimer> ret; 61 const GrGLInterface* gl = ctx->gl(); 62 if (gl->fExtensions.has("GL_EXT_disjoint_timer_query")) { 63 ret.reset(new GLGpuTimer(true, ctx, "EXT")); 64 } else if (kGL_GrGLStandard == gl->fStandard && 65 (GrGLGetVersion(gl) > GR_GL_VER(3,3) || gl->fExtensions.has("GL_ARB_timer_query"))) { 66 ret.reset(new GLGpuTimer(false, ctx)); 67 } else if (gl->fExtensions.has("GL_EXT_timer_query")) { 68 ret.reset(new GLGpuTimer(false, ctx, "EXT")); 69 } 70 if (ret && !ret->validate()) { 71 ret = nullptr; 72 } 73 return ret; 74#else 75 return nullptr; 76#endif 77} 78 79#ifdef SK_GL 80GLGpuTimer::GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext* ctx, const char* ext) 81 : INHERITED(disjointSupport) { 82 ctx->getGLProcAddress(&fGLGetIntegerv, "glGetIntegerv"); 83 ctx->getGLProcAddress(&fGLGenQueries, "glGenQueries", ext); 84 ctx->getGLProcAddress(&fGLDeleteQueries, "glDeleteQueries", ext); 85 ctx->getGLProcAddress(&fGLBeginQuery, "glBeginQuery", ext); 86 ctx->getGLProcAddress(&fGLEndQuery, "glEndQuery", ext); 87 ctx->getGLProcAddress(&fGLGetQueryObjectuiv, "glGetQueryObjectuiv", ext); 88 ctx->getGLProcAddress(&fGLGetQueryObjectui64v, "glGetQueryObjectui64v", ext); 89} 90 91bool GLGpuTimer::validate() const { 92 return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery && 93 fGLGetQueryObjectuiv && fGLGetQueryObjectui64v; 94} 95#endif 96 97sk_gpu_test::PlatformTimerQuery GLGpuTimer::onQueueTimerStart() const { 98 GrGLuint queryID; 99 fGLGenQueries(1, &queryID); 100 if (!queryID) { 101 return sk_gpu_test::kInvalidTimerQuery; 102 } 103 if (this->disjointSupport()) { 104 // Clear the disjoint flag. 105 GrGLint disjoint; 106 fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); 107 } 108 fGLBeginQuery(GL_TIME_ELAPSED, queryID); 109 return static_cast<sk_gpu_test::PlatformTimerQuery>(queryID); 110} 111 112void GLGpuTimer::onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const { 113 if (sk_gpu_test::kInvalidTimerQuery == platformTimer) { 114 return; 115 } 116 fGLEndQuery(GL_TIME_ELAPSED); 117} 118 119sk_gpu_test::GpuTimer::QueryStatus 120GLGpuTimer::checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer) { 121 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 122 if (!queryID) { 123 return QueryStatus::kInvalid; 124 } 125 GrGLuint available = 0; 126 fGLGetQueryObjectuiv(queryID, GL_QUERY_RESULT_AVAILABLE, &available); 127 if (!available) { 128 return QueryStatus::kPending; 129 } 130 if (this->disjointSupport()) { 131 GrGLint disjoint = 1; 132 fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); 133 if (disjoint) { 134 return QueryStatus::kDisjoint; 135 } 136 } 137 return QueryStatus::kAccurate; 138} 139 140std::chrono::nanoseconds GLGpuTimer::getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer) { 141 SkASSERT(this->checkQueryStatus(platformTimer) >= QueryStatus::kDisjoint); 142 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 143 GrGLuint64 nanoseconds; 144 fGLGetQueryObjectui64v(queryID, GL_QUERY_RESULT, &nanoseconds); 145 return std::chrono::nanoseconds(nanoseconds); 146} 147 148void GLGpuTimer::deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer) { 149 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 150 fGLDeleteQueries(1, &queryID); 151} 152 153static_assert(sizeof(GrGLuint) <= sizeof(sk_gpu_test::PlatformTimerQuery)); 154 155} // anonymous namespace 156 157namespace sk_gpu_test { 158 159GLTestContext::GLTestContext() : TestContext() {} 160 161GLTestContext::~GLTestContext() { 162 SkASSERT(!fGLInterface); 163 SkASSERT(!fOriginalGLInterface); 164} 165 166bool GLTestContext::isValid() const { 167#ifdef SK_GL 168 return SkToBool(this->gl()); 169#else 170 return fWasInitialized; 171#endif 172} 173 174static bool fence_is_supported(const GLTestContext* ctx) { 175#ifdef SK_GL 176 if (kGL_GrGLStandard == ctx->gl()->fStandard) { 177 if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3, 2) && 178 !ctx->gl()->hasExtension("GL_ARB_sync")) { 179 return false; 180 } 181 return true; 182 } else { 183 if (ctx->gl()->hasExtension("GL_APPLE_sync")) { 184 return true; 185 } else if (ctx->gl()->hasExtension("GL_NV_fence")) { 186 return true; 187 } else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) { 188 return true; 189 } else { 190 return false; 191 } 192 } 193#else 194 return false; 195#endif 196} 197 198void GLTestContext::init(sk_sp<const GrGLInterface> gl) { 199 fGLInterface = std::move(gl); 200 fOriginalGLInterface = fGLInterface; 201 fFenceSupport = fence_is_supported(this); 202 fGpuTimer = GLGpuTimer::MakeIfSupported(this); 203#ifndef SK_GL 204 fWasInitialized = true; 205#endif 206} 207 208void GLTestContext::teardown() { 209 fGLInterface.reset(); 210 fOriginalGLInterface.reset(); 211 INHERITED::teardown(); 212} 213 214void GLTestContext::testAbandon() { 215 INHERITED::testAbandon(); 216#ifdef SK_GL 217 if (fGLInterface) { 218 fGLInterface->abandon(); 219 fOriginalGLInterface->abandon(); 220 } 221#endif 222} 223 224void GLTestContext::finish() { 225#ifdef SK_GL 226 if (fGLInterface) { 227 GR_GL_CALL(fGLInterface.get(), Finish()); 228 } 229#endif 230} 231 232void GLTestContext::overrideVersion(const char* version, const char* shadingLanguageVersion) { 233#ifdef SK_GL 234 // GrGLFunction has both a limited capture size and doesn't call a destructor when it is 235 // initialized with a lambda. So here we're trusting fOriginalGLInterface will be kept alive. 236 auto getString = [wrapped = &fOriginalGLInterface->fFunctions.fGetString, 237 version, 238 shadingLanguageVersion](GrGLenum name) { 239 if (name == GR_GL_VERSION) { 240 return reinterpret_cast<const GrGLubyte*>(version); 241 } else if (name == GR_GL_SHADING_LANGUAGE_VERSION) { 242 return reinterpret_cast<const GrGLubyte*>(shadingLanguageVersion); 243 } 244 return (*wrapped)(name); 245 }; 246 auto newInterface = sk_make_sp<GrGLInterface>(*fOriginalGLInterface); 247 newInterface->fFunctions.fGetString = getString; 248 fGLInterface = std::move(newInterface); 249#endif 250}; 251 252sk_sp<GrDirectContext> GLTestContext::makeContext(const GrContextOptions& options) { 253#ifdef SK_GL 254 return GrDirectContext::MakeGL(fGLInterface, options); 255#else 256 return nullptr; 257#endif 258} 259 260} // namespace sk_gpu_test 261