From d416a5b10ff9e6d4f55a1f5b0419722132d68ff3 Mon Sep 17 00:00:00 2001 From: cdalton Date: Tue, 23 Jun 2015 13:23:44 -0700 Subject: Implement SkGLContext swapBuffers with fence syncs Improves the GPU measuring accuracy of nanobench by using fence syncs. Fence syncs are very widely supported and available on almost every platform. NO_MERGE_BUILDS BUG=skia: Review URL: https://codereview.chromium.org/1194783003 --- src/gpu/SkGpuFenceSync.h | 29 +++++ src/gpu/gl/GrGLAssembleInterface.h | 1 - src/gpu/gl/SkGLContext.cpp | 136 ++++++++++++++++++++++- src/gpu/gl/SkNullGLContext.cpp | 6 +- src/gpu/gl/angle/SkANGLEGLContext.cpp | 18 ++- src/gpu/gl/debug/SkDebugGLContext.cpp | 4 +- src/gpu/gl/debug/SkDebugGLContext.h | 6 +- src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp | 88 +++++++++++++-- src/gpu/gl/glx/SkCreatePlatformGLContext_glx.cpp | 24 ++-- src/gpu/gl/iOS/SkCreatePlatformGLContext_iOS.mm | 36 ++++-- src/gpu/gl/mac/SkCreatePlatformGLContext_mac.cpp | 36 ++++-- src/gpu/gl/mesa/SkMesaGLContext.cpp | 18 ++- src/gpu/gl/mesa/SkMesaGLContext.h | 6 +- src/gpu/gl/win/SkCreatePlatformGLContext_win.cpp | 24 ++-- 14 files changed, 365 insertions(+), 67 deletions(-) create mode 100644 src/gpu/SkGpuFenceSync.h (limited to 'src') diff --git a/src/gpu/SkGpuFenceSync.h b/src/gpu/SkGpuFenceSync.h new file mode 100644 index 0000000000..b78398fed8 --- /dev/null +++ b/src/gpu/SkGpuFenceSync.h @@ -0,0 +1,29 @@ + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkGpuFenceSync_DEFINED +#define SkGpuFenceSync_DEFINED + +#include "SkTypes.h" + +typedef void* SkPlatformGpuFence; + +/* + * This class provides an interface to interact with fence syncs. A fence sync is an object that the + * client can insert into the GPU command stream, and then at any future time, wait until all + * commands that were issued before the fence have completed. + */ +class SkGpuFenceSync { +public: + virtual SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const = 0; + virtual bool flushAndWaitFence(SkPlatformGpuFence) const = 0; + virtual void deleteFence(SkPlatformGpuFence) const = 0; + + virtual ~SkGpuFenceSync() {} +}; + +#endif diff --git a/src/gpu/gl/GrGLAssembleInterface.h b/src/gpu/gl/GrGLAssembleInterface.h index aa0fbcadd5..2a4835be38 100644 --- a/src/gpu/gl/GrGLAssembleInterface.h +++ b/src/gpu/gl/GrGLAssembleInterface.h @@ -8,7 +8,6 @@ #include "gl/GrGLInterface.h" -typedef void(*GrGLFuncPtr)(); typedef GrGLFuncPtr (*GrGLGetProc)(void* ctx, const char name[]); diff --git a/src/gpu/gl/SkGLContext.cpp b/src/gpu/gl/SkGLContext.cpp index 7cc728d62e..8975a989d1 100644 --- a/src/gpu/gl/SkGLContext.cpp +++ b/src/gpu/gl/SkGLContext.cpp @@ -7,16 +7,148 @@ */ #include "gl/SkGLContext.h" #include "GrGLUtil.h" +#include "SkGpuFenceSync.h" -SkGLContext::SkGLContext() { +class SkGLContext::GLFenceSync : public SkGpuFenceSync { +public: + static GLFenceSync* CreateIfSupported(const SkGLContext*); + + SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override; + bool flushAndWaitFence(SkPlatformGpuFence fence) const override; + void deleteFence(SkPlatformGpuFence fence) const override; + +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; + + typedef struct __GLsync *GLsync; + + typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield); + typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64); + typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync); + + GLFenceSyncProc fGLFenceSync; + GLClientWaitSyncProc fGLClientWaitSync; + GLDeleteSyncProc fGLDeleteSync; + + typedef SkGpuFenceSync INHERITED; +}; + +SkGLContext::SkGLContext() + : fCurrentFenceIdx(0) { + memset(fFrameFences, 0, sizeof(fFrameFences)); } SkGLContext::~SkGLContext() { - SkASSERT(NULL == fGL.get()); // Subclass should destroy the interface. + // Subclass should call teardown. +#ifdef SK_DEBUG + for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) { + SkASSERT(0 == fFrameFences[i]); + } +#endif + SkASSERT(NULL == fGL.get()); + SkASSERT(NULL == fFenceSync.get()); +} + +void SkGLContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) { + SkASSERT(!fGL.get()); + fGL.reset(gl); + fFenceSync.reset(fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this)); +} + +void SkGLContext::teardown() { + if (fFenceSync) { + for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) { + if (fFrameFences[i]) { + fFenceSync->deleteFence(fFrameFences[i]); + fFrameFences[i] = 0; + } + } + fFenceSync.reset(NULL); + } + + fGL.reset(NULL); +} + +void SkGLContext::makeCurrent() const { + this->onPlatformMakeCurrent(); +} + +void SkGLContext::swapBuffers() { + if (!fFenceSync) { + // Fallback on the platform SwapBuffers method for synchronization. This may have no effect. + this->onPlatformSwapBuffers(); + return; + } + + if (fFrameFences[fCurrentFenceIdx]) { + if (!fFenceSync->flushAndWaitFence(fFrameFences[fCurrentFenceIdx])) { + SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n"); + } + fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]); + } + + fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence(); + fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences); } void SkGLContext::testAbandon() { if (fGL) { fGL->abandon(); } + if (fFenceSync) { + memset(fFrameFences, 0, sizeof(fFrameFences)); + } +} + +SkGLContext::GLFenceSync* SkGLContext::GLFenceSync::CreateIfSupported(const SkGLContext* ctx) { + SkAutoTDelete ret(SkNEW(GLFenceSync)); + + if (kGL_GrGLStandard == ctx->gl()->fStandard) { + const GrGLubyte* versionStr; + SK_GL_RET(*ctx, versionStr, GetString(GR_GL_VERSION)); + GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast(versionStr)); + if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) { + return NULL; + } + ret->fGLFenceSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glFenceSync")); + ret->fGLClientWaitSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glClientWaitSync")); + ret->fGLDeleteSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glDeleteSync")); + } else { + if (!ctx->gl()->hasExtension("GL_APPLE_sync")) { + return NULL; + } + ret->fGLFenceSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glFenceSyncAPPLE")); + ret->fGLClientWaitSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE")); + ret->fGLDeleteSync = reinterpret_cast( + ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE")); + } + + if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) { + return NULL; + } + + return ret.detach(); +} + +SkPlatformGpuFence SkGLContext::GLFenceSync::insertFence() const { + return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +bool SkGLContext::GLFenceSync::flushAndWaitFence(SkPlatformGpuFence fence) const { + GLsync glsync = static_cast(fence); + return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1); +} + +void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const { + GLsync glsync = static_cast(fence); + fGLDeleteSync(glsync); } diff --git a/src/gpu/gl/SkNullGLContext.cpp b/src/gpu/gl/SkNullGLContext.cpp index 7ced85e89e..1d67578cae 100644 --- a/src/gpu/gl/SkNullGLContext.cpp +++ b/src/gpu/gl/SkNullGLContext.cpp @@ -547,7 +547,7 @@ SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) { SkNullGLContext::SkNullGLContext() { fState = SkNEW(ContextState); GrGLInterface* interface = create_null_interface(fState); - fGL.reset(interface); + this->init(interface); #if GR_GL_PER_GL_FUNC_CALLBACK interface->fCallback = set_current_context_from_interface; interface->fCallbackData = reinterpret_cast(fState); @@ -555,8 +555,8 @@ SkNullGLContext::SkNullGLContext() { } SkNullGLContext::~SkNullGLContext() { - fGL.reset(NULL); + this->teardown(); fState->unref(); } -void SkNullGLContext::makeCurrent() const { set_current_context(fState); } +void SkNullGLContext::onPlatformMakeCurrent() const { set_current_context(fState); } diff --git a/src/gpu/gl/angle/SkANGLEGLContext.cpp b/src/gpu/gl/angle/SkANGLEGLContext.cpp index cea2adf989..f6321988aa 100644 --- a/src/gpu/gl/angle/SkANGLEGLContext.cpp +++ b/src/gpu/gl/angle/SkANGLEGLContext.cpp @@ -96,25 +96,27 @@ SkANGLEGLContext::SkANGLEGLContext() eglMakeCurrent(fDisplay, fSurface, fSurface, fContext); - fGL.reset(GrGLCreateANGLEInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateANGLEInterface()); + if (NULL == gl.get()) { SkDebugf("Could not create ANGLE GL interface!\n"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Could not validate ANGLE GL interface!\n"); this->destroyGLContext(); return; } + + this->init(gl.detach()); } SkANGLEGLContext::~SkANGLEGLContext() { + this->teardown(); this->destroyGLContext(); } void SkANGLEGLContext::destroyGLContext() { - fGL.reset(NULL); if (fDisplay) { eglMakeCurrent(fDisplay, 0, 0, 0); @@ -133,14 +135,18 @@ void SkANGLEGLContext::destroyGLContext() { } } -void SkANGLEGLContext::makeCurrent() const { +void SkANGLEGLContext::onPlatformMakeCurrent() const { if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { SkDebugf("Could not set the context.\n"); } } -void SkANGLEGLContext::swapBuffers() const { +void SkANGLEGLContext::onPlatformSwapBuffers() const { if (!eglSwapBuffers(fDisplay, fSurface)) { SkDebugf("Could not complete eglSwapBuffers.\n"); } } + +GrGLFuncPtr SkANGLEGLContext::onPlatformGetProcAddress(const char* name) const { + return eglGetProcAddress(name); +} diff --git a/src/gpu/gl/debug/SkDebugGLContext.cpp b/src/gpu/gl/debug/SkDebugGLContext.cpp index ae55104d46..531e6c3ab8 100644 --- a/src/gpu/gl/debug/SkDebugGLContext.cpp +++ b/src/gpu/gl/debug/SkDebugGLContext.cpp @@ -9,9 +9,9 @@ #include "gl/debug/SkDebugGLContext.h" SkDebugGLContext::SkDebugGLContext() { - fGL.reset(GrGLCreateDebugInterface()); + this->init(GrGLCreateDebugInterface()); } SkDebugGLContext::~SkDebugGLContext() { - fGL.reset(NULL); + this->teardown(); } diff --git a/src/gpu/gl/debug/SkDebugGLContext.h b/src/gpu/gl/debug/SkDebugGLContext.h index 577953223a..6a4d9fc38b 100644 --- a/src/gpu/gl/debug/SkDebugGLContext.h +++ b/src/gpu/gl/debug/SkDebugGLContext.h @@ -13,8 +13,6 @@ class SkDebugGLContext : public SkGLContext { public: ~SkDebugGLContext() override; - void makeCurrent() const override {} - void swapBuffers() const override {} static SkDebugGLContext* Create(GrGLStandard forcedGpuAPI) { if (kGLES_GrGLStandard == forcedGpuAPI) { @@ -23,6 +21,10 @@ public: return SkNEW(SkDebugGLContext); } private: + void onPlatformMakeCurrent() const override {} + void onPlatformSwapBuffers() const override {} + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return NULL; } + SkDebugGLContext(); }; diff --git a/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp b/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp index d57f761008..9ed57a37a3 100644 --- a/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp +++ b/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp @@ -8,20 +8,42 @@ #include "gl/SkGLContext.h" #include + +#define EGL_EGLEXT_PROTOTYPES #include +#include namespace { +// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync. +class SkEGLFenceSync : public SkGpuFenceSync { +public: + static SkEGLFenceSync* CreateIfSupported(EGLDisplay); + + SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override; + bool flushAndWaitFence(SkPlatformGpuFence fence) const override; + void deleteFence(SkPlatformGpuFence fence) const override; + +private: + SkEGLFenceSync(EGLDisplay display) : fDisplay(display) {} + + EGLDisplay fDisplay; + + typedef SkGpuFenceSync INHERITED; +}; + class EGLGLContext : public SkGLContext { public: EGLGLContext(GrGLStandard forcedGpuAPI); ~EGLGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; private: void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; + EGLContext fContext; EGLDisplay fDisplay; EGLSurface fSurface; @@ -69,7 +91,9 @@ EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI) } SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI); - for (; NULL == fGL.get() && api < apiLimit; ++api) { + SkAutoTUnref gl; + + for (; NULL == gl.get() && api < apiLimit; ++api) { fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint majorVersion; @@ -134,27 +158,30 @@ EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI) continue; } - fGL.reset(GrGLCreateNativeInterface()); - if (NULL == fGL.get()) { + gl.reset(GrGLCreateNativeInterface()); + if (NULL == gl.get()) { SkDebugf("Failed to create gl interface.\n"); this->destroyGLContext(); continue; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Failed to validate gl interface.\n"); this->destroyGLContext(); continue; } + + this->init(gl.detach(), SkEGLFenceSync::CreateIfSupported(fDisplay)); + break; } } EGLGLContext::~EGLGLContext() { + this->teardown(); this->destroyGLContext(); } void EGLGLContext::destroyGLContext() { - fGL.reset(NULL); if (fDisplay) { eglMakeCurrent(fDisplay, 0, 0, 0); @@ -174,18 +201,61 @@ void EGLGLContext::destroyGLContext() { } -void EGLGLContext::makeCurrent() const { +void EGLGLContext::onPlatformMakeCurrent() const { if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { SkDebugf("Could not set the context.\n"); } } -void EGLGLContext::swapBuffers() const { +void EGLGLContext::onPlatformSwapBuffers() const { if (!eglSwapBuffers(fDisplay, fSurface)) { SkDebugf("Could not complete eglSwapBuffers.\n"); } } +GrGLFuncPtr EGLGLContext::onPlatformGetProcAddress(const char* procName) const { + return eglGetProcAddress(procName); +} + +static bool supports_egl_extension(EGLDisplay display, const char* extension) { + int extensionLength = strlen(extension); + const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS); + while (const char* match = strstr(extensionsStr, extension)) { + // Ensure the string we found is its own extension, not a substring of a larger extension + // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2). + if ((match == extensionsStr || match[-1] == ' ') && + (match[extensionLength] == ' ' || match[extensionLength] == '\0')) { + return true; + } + extensionsStr = match + extensionLength; + } + return false; +} + +SkEGLFenceSync* SkEGLFenceSync::CreateIfSupported(EGLDisplay display) { + if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) { + return NULL; + } + return SkNEW_ARGS(SkEGLFenceSync, (display)); +} + +SkPlatformGpuFence SkEGLFenceSync::insertFence() const { + return eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, NULL); +} + +bool SkEGLFenceSync::flushAndWaitFence(SkPlatformGpuFence platformFence) const { + EGLSyncKHR eglsync = static_cast(platformFence); + return EGL_CONDITION_SATISFIED_KHR == eglClientWaitSyncKHR(fDisplay, + eglsync, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, + EGL_FOREVER_KHR); +} + +void SkEGLFenceSync::deleteFence(SkPlatformGpuFence platformFence) const { + EGLSyncKHR eglsync = static_cast(platformFence); + eglDestroySyncKHR(fDisplay, eglsync); +} + } // anonymous namespace SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) { diff --git a/src/gpu/gl/glx/SkCreatePlatformGLContext_glx.cpp b/src/gpu/gl/glx/SkCreatePlatformGLContext_glx.cpp index 8006d498aa..7933757186 100644 --- a/src/gpu/gl/glx/SkCreatePlatformGLContext_glx.cpp +++ b/src/gpu/gl/glx/SkCreatePlatformGLContext_glx.cpp @@ -48,12 +48,14 @@ class GLXGLContext : public SkGLContext { public: GLXGLContext(GrGLStandard forcedGpuAPI); ~GLXGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; private: void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; + GLXContext fContext; Display* fDisplay; Pixmap fPixmap; @@ -267,27 +269,29 @@ GLXGLContext::GLXGLContext(GrGLStandard forcedGpuAPI) return; } - fGL.reset(GrGLCreateNativeInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateNativeInterface()); + if (NULL == gl.get()) { SkDebugf("Failed to create gl interface"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Failed to validate gl interface"); this->destroyGLContext(); return; } + + this->init(gl.detach()); } GLXGLContext::~GLXGLContext() { + this->teardown(); this->destroyGLContext(); } void GLXGLContext::destroyGLContext() { - fGL.reset(NULL); if (fDisplay) { glXMakeCurrent(fDisplay, 0, 0); @@ -311,16 +315,20 @@ void GLXGLContext::destroyGLContext() { } } -void GLXGLContext::makeCurrent() const { +void GLXGLContext::onPlatformMakeCurrent() const { if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { SkDebugf("Could not set the context.\n"); } } -void GLXGLContext::swapBuffers() const { +void GLXGLContext::onPlatformSwapBuffers() const { glXSwapBuffers(fDisplay, fGlxPixmap); } +GrGLFuncPtr GLXGLContext::onPlatformGetProcAddress(const char* procName) const { + return glXGetProcAddress(reinterpret_cast(procName)); +} + } // anonymous namespace SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) { diff --git a/src/gpu/gl/iOS/SkCreatePlatformGLContext_iOS.mm b/src/gpu/gl/iOS/SkCreatePlatformGLContext_iOS.mm index 884216845c..08e6f239ee 100644 --- a/src/gpu/gl/iOS/SkCreatePlatformGLContext_iOS.mm +++ b/src/gpu/gl/iOS/SkCreatePlatformGLContext_iOS.mm @@ -8,6 +8,7 @@ #include "gl/SkGLContext.h" #import +#include #define EAGLCTX ((EAGLContext*)(fEAGLContext)) @@ -17,40 +18,50 @@ class IOSGLContext : public SkGLContext { public: IOSGLContext(); ~IOSGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; private: void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; + void* fEAGLContext; + void* fGLLibrary; }; IOSGLContext::IOSGLContext() - : fEAGLContext(NULL) { + : fEAGLContext(NULL) + , fGLLibrary(RTLD_DEFAULT) { fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; [EAGLContext setCurrentContext:EAGLCTX]; - fGL.reset(GrGLCreateNativeInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateNativeInterface()); + if (NULL == gl.get()) { SkDebugf("Failed to create gl interface"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Failed to validate gl interface"); this->destroyGLContext(); return; } + + fGLLibrary = dlopen( + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", + RTLD_LAZY); + + this->init(gl.detach()); } IOSGLContext::~IOSGLContext() { + this->teardown(); this->destroyGLContext(); } void IOSGLContext::destroyGLContext() { - fGL.reset(NULL); if (fEAGLContext) { if ([EAGLContext currentContext] == EAGLCTX) { [EAGLContext setCurrentContext:nil]; @@ -58,16 +69,23 @@ void IOSGLContext::destroyGLContext() { [EAGLCTX release]; fEAGLContext = NULL; } + if (RTLD_DEFAULT != fGLLibrary) { + dlclose(fGLLibrary); + } } -void IOSGLContext::makeCurrent() const { +void IOSGLContext::onPlatformMakeCurrent() const { if (![EAGLContext setCurrentContext:EAGLCTX]) { SkDebugf("Could not set the context.\n"); } } -void IOSGLContext::swapBuffers() const { } +void IOSGLContext::onPlatformSwapBuffers() const { } + +GrGLFuncPtr IOSGLContext::onPlatformGetProcAddress(const char* procName) const { + return reinterpret_cast(dlsym(fGLLibrary, procName)); +} } // anonymous namespace diff --git a/src/gpu/gl/mac/SkCreatePlatformGLContext_mac.cpp b/src/gpu/gl/mac/SkCreatePlatformGLContext_mac.cpp index 436c53f0bb..d2d8569938 100644 --- a/src/gpu/gl/mac/SkCreatePlatformGLContext_mac.cpp +++ b/src/gpu/gl/mac/SkCreatePlatformGLContext_mac.cpp @@ -9,23 +9,28 @@ #include "AvailabilityMacros.h" #include +#include namespace { class MacGLContext : public SkGLContext { public: MacGLContext(); ~MacGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; private: void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; + CGLContextObj fContext; + void* fGLLibrary; }; MacGLContext::MacGLContext() - : fContext(NULL) { + : fContext(NULL) + , fGLLibrary(RTLD_DEFAULT) { CGLPixelFormatAttribute attributes[] = { #if MAC_OS_X_VERSION_10_7 kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, @@ -53,39 +58,52 @@ MacGLContext::MacGLContext() CGLSetCurrentContext(fContext); - fGL.reset(GrGLCreateNativeInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateNativeInterface()); + if (NULL == gl.get()) { SkDebugf("Context could not create GL interface.\n"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Context could not validate GL interface.\n"); this->destroyGLContext(); return; } + + fGLLibrary = dlopen( + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", + RTLD_LAZY); + + this->init(gl.detach()); } MacGLContext::~MacGLContext() { + this->teardown(); this->destroyGLContext(); } void MacGLContext::destroyGLContext() { - fGL.reset(NULL); if (fContext) { CGLReleaseContext(fContext); fContext = NULL; } + if (RTLD_DEFAULT != fGLLibrary) { + dlclose(fGLLibrary); + } } -void MacGLContext::makeCurrent() const { +void MacGLContext::onPlatformMakeCurrent() const { CGLSetCurrentContext(fContext); } -void MacGLContext::swapBuffers() const { +void MacGLContext::onPlatformSwapBuffers() const { CGLFlushDrawable(fContext); } +GrGLFuncPtr MacGLContext::onPlatformGetProcAddress(const char* procName) const { + return reinterpret_cast(dlsym(fGLLibrary, procName)); +} + } // anonymous namespace SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) { diff --git a/src/gpu/gl/mesa/SkMesaGLContext.cpp b/src/gpu/gl/mesa/SkMesaGLContext.cpp index 1fac5fadd6..701cc0d320 100644 --- a/src/gpu/gl/mesa/SkMesaGLContext.cpp +++ b/src/gpu/gl/mesa/SkMesaGLContext.cpp @@ -50,26 +50,28 @@ SkMesaGLContext::SkMesaGLContext() return; } - fGL.reset(GrGLCreateMesaInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateMesaInterface()); + if (NULL == gl.get()) { SkDebugf("Could not create GL interface!\n"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Could not validate GL interface!\n"); this->destroyGLContext(); return; } + + this->init(gl.detach()); } SkMesaGLContext::~SkMesaGLContext() { + this->teardown(); this->destroyGLContext(); } void SkMesaGLContext::destroyGLContext() { - fGL.reset(NULL); if (fImage) { sk_free(fImage); fImage = NULL; @@ -83,7 +85,7 @@ void SkMesaGLContext::destroyGLContext() { -void SkMesaGLContext::makeCurrent() const { +void SkMesaGLContext::onPlatformMakeCurrent() const { if (fContext) { if (!OSMesaMakeCurrent((OSMesaContext)fContext, fImage, GR_GL_UNSIGNED_BYTE, gBOGUS_SIZE, gBOGUS_SIZE)) { @@ -92,4 +94,8 @@ void SkMesaGLContext::makeCurrent() const { } } -void SkMesaGLContext::swapBuffers() const { } +void SkMesaGLContext::onPlatformSwapBuffers() const { } + +GrGLFuncPtr SkMesaGLContext::onPlatformGetProcAddress(const char* procName) const { + return OSMesaGetProcAddress(procName); +} diff --git a/src/gpu/gl/mesa/SkMesaGLContext.h b/src/gpu/gl/mesa/SkMesaGLContext.h index bf0c7e9060..fa3df7b7c7 100644 --- a/src/gpu/gl/mesa/SkMesaGLContext.h +++ b/src/gpu/gl/mesa/SkMesaGLContext.h @@ -18,8 +18,6 @@ private: public: ~SkMesaGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; static SkMesaGLContext* Create(GrGLStandard forcedGpuAPI) { if (kGLES_GrGLStandard == forcedGpuAPI) { @@ -37,6 +35,10 @@ private: SkMesaGLContext(); void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; + Context fContext; GrGLubyte *fImage; }; diff --git a/src/gpu/gl/win/SkCreatePlatformGLContext_win.cpp b/src/gpu/gl/win/SkCreatePlatformGLContext_win.cpp index d387ef4922..8a4c5db5b3 100644 --- a/src/gpu/gl/win/SkCreatePlatformGLContext_win.cpp +++ b/src/gpu/gl/win/SkCreatePlatformGLContext_win.cpp @@ -21,12 +21,14 @@ class WinGLContext : public SkGLContext { public: WinGLContext(GrGLStandard forcedGpuAPI); ~WinGLContext() override; - void makeCurrent() const override; - void swapBuffers() const override; private: void destroyGLContext(); + void onPlatformMakeCurrent() const override; + void onPlatformSwapBuffers() const override; + GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override; + HWND fWindow; HDC fDeviceContext; HGLRC fGlRenderContext; @@ -113,25 +115,27 @@ WinGLContext::WinGLContext(GrGLStandard forcedGpuAPI) return; } - fGL.reset(GrGLCreateNativeInterface()); - if (NULL == fGL.get()) { + SkAutoTUnref gl(GrGLCreateNativeInterface()); + if (NULL == gl.get()) { SkDebugf("Could not create GL interface.\n"); this->destroyGLContext(); return; } - if (!fGL->validate()) { + if (!gl->validate()) { SkDebugf("Could not validate GL interface.\n"); this->destroyGLContext(); return; } + + this->init(gl.detach()); } WinGLContext::~WinGLContext() { + this->teardown(); this->destroyGLContext(); } void WinGLContext::destroyGLContext() { - fGL.reset(NULL); SkSafeSetNull(fPbufferContext); if (fGlRenderContext) { wglDeleteContext(fGlRenderContext); @@ -147,7 +151,7 @@ void WinGLContext::destroyGLContext() { } } -void WinGLContext::makeCurrent() const { +void WinGLContext::onPlatformMakeCurrent() const { HDC dc; HGLRC glrc; @@ -164,7 +168,7 @@ void WinGLContext::makeCurrent() const { } } -void WinGLContext::swapBuffers() const { +void WinGLContext::onPlatformSwapBuffers() const { HDC dc; if (NULL == fPbufferContext) { @@ -177,6 +181,10 @@ void WinGLContext::swapBuffers() const { } } +GrGLFuncPtr WinGLContext::onPlatformGetProcAddress(const char* name) const { + return reinterpret_cast(wglGetProcAddress(name)); +} + } // anonymous namespace SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) { -- cgit v1.2.3