1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "gl/SkGLContext.h" 9 #include "GrGLUtil.h" 10 #include "SkGpuFenceSync.h" 11 12 class SkGLContext::GLFenceSync : public SkGpuFenceSync { 13 public: 14 static GLFenceSync* CreateIfSupported(const SkGLContext*); 15 16 SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override; 17 bool waitFence(SkPlatformGpuFence fence, bool flush) const override; 18 void deleteFence(SkPlatformGpuFence fence) const override; 19 20 private: 21 GLFenceSync() {} 22 23 static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117; 24 static const GrGLenum GL_WAIT_FAILED = 0x911d; 25 static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001; 26 27 typedef struct __GLsync *GLsync; 28 29 typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield); 30 typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64); 31 typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync); 32 33 GLFenceSyncProc fGLFenceSync; 34 GLClientWaitSyncProc fGLClientWaitSync; 35 GLDeleteSyncProc fGLDeleteSync; 36 37 typedef SkGpuFenceSync INHERITED; 38 }; 39 40 SkGLContext::SkGLContext() 41 : fCurrentFenceIdx(0) { 42 memset(fFrameFences, 0, sizeof(fFrameFences)); 43 } 44 45 SkGLContext::~SkGLContext() { 46 // Subclass should call teardown. 47 #ifdef SK_DEBUG 48 for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) { 49 SkASSERT(0 == fFrameFences[i]); 50 } 51 #endif 52 SkASSERT(nullptr == fGL.get()); 53 SkASSERT(nullptr == fFenceSync.get()); 54 } 55 56 void SkGLContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) { 57 SkASSERT(!fGL.get()); 58 fGL.reset(gl); 59 fFenceSync.reset(fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this)); 60 } 61 62 void SkGLContext::teardown() { 63 if (fFenceSync) { 64 for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) { 65 if (fFrameFences[i]) { 66 fFenceSync->deleteFence(fFrameFences[i]); 67 fFrameFences[i] = 0; 68 } 69 } 70 fFenceSync.reset(nullptr); 71 } 72 73 fGL.reset(nullptr); 74 } 75 76 void SkGLContext::makeCurrent() const { 77 this->onPlatformMakeCurrent(); 78 } 79 80 void SkGLContext::swapBuffers() { 81 this->onPlatformSwapBuffers(); 82 } 83 84 void SkGLContext::waitOnSyncOrSwap() { 85 if (!fFenceSync) { 86 // Fallback on the platform SwapBuffers method for synchronization. This may have no effect. 87 this->swapBuffers(); 88 return; 89 } 90 91 if (fFrameFences[fCurrentFenceIdx]) { 92 if (!fFenceSync->waitFence(fFrameFences[fCurrentFenceIdx], true)) { 93 SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n"); 94 } 95 fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]); 96 } 97 98 fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence(); 99 fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences); 100 } 101 102 void SkGLContext::testAbandon() { 103 if (fGL) { 104 fGL->abandon(); 105 } 106 if (fFenceSync) { 107 memset(fFrameFences, 0, sizeof(fFrameFences)); 108 } 109 } 110 111 SkGLContext::GLFenceSync* SkGLContext::GLFenceSync::CreateIfSupported(const SkGLContext* ctx) { 112 SkAutoTDelete<GLFenceSync> ret(new GLFenceSync); 113 114 if (kGL_GrGLStandard == ctx->gl()->fStandard) { 115 const GrGLubyte* versionStr; 116 SK_GL_RET(*ctx, versionStr, GetString(GR_GL_VERSION)); 117 GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast<const char*>(versionStr)); 118 if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) { 119 return nullptr; 120 } 121 ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>( 122 ctx->onPlatformGetProcAddress("glFenceSync")); 123 ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>( 124 ctx->onPlatformGetProcAddress("glClientWaitSync")); 125 ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>( 126 ctx->onPlatformGetProcAddress("glDeleteSync")); 127 } else { 128 if (!ctx->gl()->hasExtension("GL_APPLE_sync")) { 129 return nullptr; 130 } 131 ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>( 132 ctx->onPlatformGetProcAddress("glFenceSyncAPPLE")); 133 ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>( 134 ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE")); 135 ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>( 136 ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE")); 137 } 138 139 if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) { 140 return nullptr; 141 } 142 143 return ret.detach(); 144 } 145 146 SkPlatformGpuFence SkGLContext::GLFenceSync::insertFence() const { 147 return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 148 } 149 150 bool SkGLContext::GLFenceSync::waitFence(SkPlatformGpuFence fence, bool flush) const { 151 GLsync glsync = static_cast<GLsync>(fence); 152 return GL_WAIT_FAILED != fGLClientWaitSync(glsync, flush ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, -1); 153 } 154 155 void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const { 156 GLsync glsync = static_cast<GLsync>(fence); 157 fGLDeleteSync(glsync); 158 } 159 160 GrGLint SkGLContext::createTextureRectangle(int width, int height, GrGLenum internalFormat, 161 GrGLenum externalFormat, GrGLenum externalType, 162 GrGLvoid* data) { 163 if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL) >= GR_GL_VER(3, 1)) && 164 !fGL->fExtensions.has("GL_ARB_texture_rectangle")) { 165 return 0; 166 } 167 168 if (GrGLGetGLSLVersion(fGL) < GR_GLSL_VER(1, 40)) { 169 return 0; 170 } 171 172 GrGLuint id; 173 GR_GL_CALL(fGL, GenTextures(1, &id)); 174 GR_GL_CALL(fGL, BindTexture(GR_GL_TEXTURE_RECTANGLE, id)); 175 GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER, 176 GR_GL_NEAREST)); 177 GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER, 178 GR_GL_NEAREST)); 179 GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S, 180 GR_GL_CLAMP_TO_EDGE)); 181 GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T, 182 GR_GL_CLAMP_TO_EDGE)); 183 GR_GL_CALL(fGL, TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0, 184 externalFormat, externalType, data)); 185 return id; 186 } 187