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 "GLTestContext.h" 9 10 #include "GpuTimer.h" 11 #include "gl/GrGLUtil.h" 12 13 namespace { 14 15 class GLFenceSync : public sk_gpu_test::FenceSync { 16 public: 17 static std::unique_ptr<GLFenceSync> MakeIfSupported(const sk_gpu_test::GLTestContext*); 18 19 sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override; 20 bool waitFence(sk_gpu_test::PlatformFence fence) const override; 21 void deleteFence(sk_gpu_test::PlatformFence fence) const override; 22 23 private: 24 GLFenceSync(const sk_gpu_test::GLTestContext*, const char* ext = ""); 25 26 bool validate() { return fGLFenceSync && fGLClientWaitSync && fGLDeleteSync; } 27 28 static constexpr GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117; 29 static constexpr GrGLenum GL_WAIT_FAILED = 0x911d; 30 static constexpr GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001; 31 32 typedef struct __GLsync *GLsync; 33 GR_STATIC_ASSERT(sizeof(GLsync) <= sizeof(sk_gpu_test::PlatformFence)); 34 35 typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield); 36 typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64); 37 typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync); 38 39 GLFenceSyncProc fGLFenceSync; 40 GLClientWaitSyncProc fGLClientWaitSync; 41 GLDeleteSyncProc fGLDeleteSync; 42 43 typedef FenceSync INHERITED; 44 }; 45 46 std::unique_ptr<GLFenceSync> GLFenceSync::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) { 47 std::unique_ptr<GLFenceSync> ret; 48 if (kGL_GrGLStandard == ctx->gl()->fStandard) { 49 if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) { 50 return nullptr; 51 } 52 ret.reset(new GLFenceSync(ctx)); 53 } else { 54 if (ctx->gl()->hasExtension("GL_APPLE_sync")) { 55 ret.reset(new GLFenceSync(ctx, "APPLE")); 56 } else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) { 57 ret.reset(new GLFenceSync(ctx)); 58 } else { 59 return nullptr; 60 } 61 } 62 if (!ret->validate()) { 63 ret = nullptr; 64 } 65 return ret; 66 } 67 68 GLFenceSync::GLFenceSync(const sk_gpu_test::GLTestContext* ctx, const char* ext) { 69 ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync"); 70 ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync"); 71 ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync"); 72 } 73 74 sk_gpu_test::PlatformFence GLFenceSync::insertFence() const { 75 __GLsync* glsync = fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 76 return reinterpret_cast<sk_gpu_test::PlatformFence>(glsync); 77 } 78 79 bool GLFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const { 80 GLsync glsync = reinterpret_cast<GLsync>(fence); 81 return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1); 82 } 83 84 void GLFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const { 85 GLsync glsync = reinterpret_cast<GLsync>(fence); 86 fGLDeleteSync(glsync); 87 } 88 89 class GLGpuTimer : public sk_gpu_test::GpuTimer { 90 public: 91 static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*); 92 93 QueryStatus checkQueryStatus(sk_gpu_test::PlatformTimerQuery) override; 94 std::chrono::nanoseconds getTimeElapsed(sk_gpu_test::PlatformTimerQuery) override; 95 void deleteQuery(sk_gpu_test::PlatformTimerQuery) override; 96 97 private: 98 GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext*, const char* ext = ""); 99 100 bool validate() const; 101 102 sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override; 103 void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override; 104 105 static constexpr GrGLenum GL_QUERY_RESULT = 0x8866; 106 static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE = 0x8867; 107 static constexpr GrGLenum GL_TIME_ELAPSED = 0x88bf; 108 static constexpr GrGLenum GL_GPU_DISJOINT = 0x8fbb; 109 110 typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*); 111 typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*); 112 typedef void (GR_GL_FUNCTION_TYPE* GLDeleteQueriesProc) (GrGLsizei, const GrGLuint*); 113 typedef void (GR_GL_FUNCTION_TYPE* GLBeginQueryProc) (GrGLenum, GrGLuint); 114 typedef void (GR_GL_FUNCTION_TYPE* GLEndQueryProc) (GrGLenum); 115 typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectuivProc) (GrGLuint, GrGLenum, GrGLuint*); 116 typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*); 117 118 GLGetIntegervProc fGLGetIntegerv; 119 GLGenQueriesProc fGLGenQueries; 120 GLDeleteQueriesProc fGLDeleteQueries; 121 GLBeginQueryProc fGLBeginQuery; 122 GLEndQueryProc fGLEndQuery; 123 GLGetQueryObjectuivProc fGLGetQueryObjectuiv; 124 GLGetQueryObjectui64vProc fGLGetQueryObjectui64v; 125 126 127 typedef sk_gpu_test::GpuTimer INHERITED; 128 }; 129 130 std::unique_ptr<GLGpuTimer> GLGpuTimer::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) { 131 std::unique_ptr<GLGpuTimer> ret; 132 const GrGLInterface* gl = ctx->gl(); 133 if (gl->fExtensions.has("GL_EXT_disjoint_timer_query")) { 134 ret.reset(new GLGpuTimer(true, ctx, "EXT")); 135 } else if (kGL_GrGLStandard == gl->fStandard && 136 (GrGLGetVersion(gl) > GR_GL_VER(3,3) || gl->fExtensions.has("GL_ARB_timer_query"))) { 137 ret.reset(new GLGpuTimer(false, ctx)); 138 } else if (gl->fExtensions.has("GL_EXT_timer_query")) { 139 ret.reset(new GLGpuTimer(false, ctx, "EXT")); 140 } 141 if (ret && !ret->validate()) { 142 ret = nullptr; 143 } 144 return ret; 145 } 146 147 GLGpuTimer::GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext* ctx, const char* ext) 148 : INHERITED(disjointSupport) { 149 ctx->getGLProcAddress(&fGLGetIntegerv, "glGetIntegerv"); 150 ctx->getGLProcAddress(&fGLGenQueries, "glGenQueries", ext); 151 ctx->getGLProcAddress(&fGLDeleteQueries, "glDeleteQueries", ext); 152 ctx->getGLProcAddress(&fGLBeginQuery, "glBeginQuery", ext); 153 ctx->getGLProcAddress(&fGLEndQuery, "glEndQuery", ext); 154 ctx->getGLProcAddress(&fGLGetQueryObjectuiv, "glGetQueryObjectuiv", ext); 155 ctx->getGLProcAddress(&fGLGetQueryObjectui64v, "glGetQueryObjectui64v", ext); 156 } 157 158 bool GLGpuTimer::validate() const { 159 return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery && 160 fGLGetQueryObjectuiv && fGLGetQueryObjectui64v; 161 } 162 163 sk_gpu_test::PlatformTimerQuery GLGpuTimer::onQueueTimerStart() const { 164 GrGLuint queryID; 165 fGLGenQueries(1, &queryID); 166 if (!queryID) { 167 return sk_gpu_test::kInvalidTimerQuery; 168 } 169 if (this->disjointSupport()) { 170 // Clear the disjoint flag. 171 GrGLint disjoint; 172 fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); 173 } 174 fGLBeginQuery(GL_TIME_ELAPSED, queryID); 175 return static_cast<sk_gpu_test::PlatformTimerQuery>(queryID); 176 } 177 178 void GLGpuTimer::onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const { 179 if (sk_gpu_test::kInvalidTimerQuery == platformTimer) { 180 return; 181 } 182 fGLEndQuery(GL_TIME_ELAPSED); 183 } 184 185 sk_gpu_test::GpuTimer::QueryStatus 186 GLGpuTimer::checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer) { 187 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 188 if (!queryID) { 189 return QueryStatus::kInvalid; 190 } 191 GrGLuint available = 0; 192 fGLGetQueryObjectuiv(queryID, GL_QUERY_RESULT_AVAILABLE, &available); 193 if (!available) { 194 return QueryStatus::kPending; 195 } 196 if (this->disjointSupport()) { 197 GrGLint disjoint = 1; 198 fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint); 199 if (disjoint) { 200 return QueryStatus::kDisjoint; 201 } 202 } 203 return QueryStatus::kAccurate; 204 } 205 206 std::chrono::nanoseconds GLGpuTimer::getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer) { 207 SkASSERT(this->checkQueryStatus(platformTimer) >= QueryStatus::kDisjoint); 208 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 209 GrGLuint64 nanoseconds; 210 fGLGetQueryObjectui64v(queryID, GL_QUERY_RESULT, &nanoseconds); 211 return std::chrono::nanoseconds(nanoseconds); 212 } 213 214 void GLGpuTimer::deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer) { 215 const GrGLuint queryID = static_cast<GrGLuint>(platformTimer); 216 fGLDeleteQueries(1, &queryID); 217 } 218 219 GR_STATIC_ASSERT(sizeof(GrGLuint) <= sizeof(sk_gpu_test::PlatformTimerQuery)); 220 221 } // anonymous namespace 222 223 namespace sk_gpu_test { 224 225 GLTestContext::GLTestContext() : TestContext() {} 226 227 GLTestContext::~GLTestContext() { 228 SkASSERT(nullptr == fGL.get()); 229 } 230 231 void GLTestContext::init(const GrGLInterface* gl, std::unique_ptr<FenceSync> fenceSync) { 232 SkASSERT(!fGL.get()); 233 fGL.reset(gl); 234 fFenceSync = fenceSync ? std::move(fenceSync) : GLFenceSync::MakeIfSupported(this); 235 fGpuTimer = GLGpuTimer::MakeIfSupported(this); 236 } 237 238 void GLTestContext::teardown() { 239 fGL.reset(nullptr); 240 INHERITED::teardown(); 241 } 242 243 void GLTestContext::testAbandon() { 244 INHERITED::testAbandon(); 245 if (fGL) { 246 fGL->abandon(); 247 } 248 } 249 250 void GLTestContext::submit() { 251 if (fGL) { 252 GR_GL_CALL(fGL.get(), Flush()); 253 } 254 } 255 256 void GLTestContext::finish() { 257 if (fGL) { 258 GR_GL_CALL(fGL.get(), Finish()); 259 } 260 } 261 262 GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat, 263 GrGLenum externalFormat, GrGLenum externalType, 264 GrGLvoid* data) { 265 if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL.get()) >= GR_GL_VER(3, 1)) && 266 !fGL->fExtensions.has("GL_ARB_texture_rectangle")) { 267 return 0; 268 } 269 270 if (GrGLGetGLSLVersion(fGL.get()) < GR_GLSL_VER(1, 40)) { 271 return 0; 272 } 273 274 GrGLuint id; 275 GR_GL_CALL(fGL.get(), GenTextures(1, &id)); 276 GR_GL_CALL(fGL.get(), BindTexture(GR_GL_TEXTURE_RECTANGLE, id)); 277 GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER, 278 GR_GL_NEAREST)); 279 GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER, 280 GR_GL_NEAREST)); 281 GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S, 282 GR_GL_CLAMP_TO_EDGE)); 283 GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T, 284 GR_GL_CLAMP_TO_EDGE)); 285 GR_GL_CALL(fGL.get(), TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0, 286 externalFormat, externalType, data)); 287 return id; 288 } 289 } // namespace sk_gpu_test 290