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