| |
| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "include/core/SkTypes.h" |
| |
| #include "tools/gpu/gl/GLTestContext.h" |
| |
| #include <AvailabilityMacros.h> |
| #include <OpenGL/OpenGL.h> |
| #include <dlfcn.h> |
| |
| namespace { |
| |
| std::function<void()> context_restorer() { |
| auto context = CGLGetCurrentContext(); |
| return [context] { CGLSetCurrentContext(context); }; |
| } |
| |
| class MacGLTestContext : public sk_gpu_test::GLTestContext { |
| public: |
| MacGLTestContext(MacGLTestContext* shareContext); |
| ~MacGLTestContext() override; |
| |
| private: |
| void destroyGLContext(); |
| |
| void onPlatformMakeNotCurrent() const override; |
| void onPlatformMakeCurrent() const override; |
| std::function<void()> onPlatformGetAutoContextRestore() const override; |
| GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; |
| |
| CGLContextObj fContext; |
| void* fGLLibrary; |
| }; |
| |
| MacGLTestContext::MacGLTestContext(MacGLTestContext* shareContext) |
| : fContext(nullptr) |
| , fGLLibrary(RTLD_DEFAULT) { |
| // We first try to request a Radeon eGPU if one is available. |
| // This will be a Radeon HD7000 and up, which includes all eGPU configs. |
| // If that fails, we try again with only the base parameters. |
| CGLPixelFormatAttribute attributes[] = { |
| // base parameters |
| #if MAC_OS_X_VERSION_10_7 |
| kCGLPFAOpenGLProfile, |
| (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, |
| #endif |
| kCGLPFADoubleBuffer, |
| |
| #if MAC_OS_X_VERSION_10_8 |
| // eGPU parameters |
| kCGLPFAAllowOfflineRenderers, // Enables e-GPU. |
| kCGLPFANoRecovery, // Disallows software rendering. |
| kCGLPFARendererID, (CGLPixelFormatAttribute)kCGLRendererATIRadeonX4000ID, // Select Radeon |
| #endif |
| (CGLPixelFormatAttribute)NULL |
| }; |
| #if MAC_OS_X_VERSION_10_8 |
| static const int kFirstEGPUParameter = 3; |
| SkASSERT(kCGLPFAAllowOfflineRenderers == attributes[kFirstEGPUParameter]); |
| #endif |
| |
| CGLPixelFormatObj pixFormat; |
| GLint npix; |
| CGLChoosePixelFormat(attributes, &pixFormat, &npix); |
| |
| #if MAC_OS_X_VERSION_10_8 |
| if (nullptr == pixFormat) { |
| // Move the NULL-termination up to remove the eGPU parameters and try again |
| attributes[kFirstEGPUParameter] = (CGLPixelFormatAttribute)NULL; |
| CGLChoosePixelFormat(attributes, &pixFormat, &npix); |
| } |
| #endif |
| if (nullptr == pixFormat) { |
| SkDebugf("CGLChoosePixelFormat failed."); |
| return; |
| } |
| |
| CGLCreateContext(pixFormat, shareContext ? shareContext->fContext : nullptr, &fContext); |
| CGLReleasePixelFormat(pixFormat); |
| |
| if (nullptr == fContext) { |
| SkDebugf("CGLCreateContext failed."); |
| return; |
| } |
| |
| SkScopeExit restorer(context_restorer()); |
| CGLSetCurrentContext(fContext); |
| |
| auto gl = GrGLMakeNativeInterface(); |
| if (!gl) { |
| SkDebugf("Context could not create GL interface.\n"); |
| this->destroyGLContext(); |
| return; |
| } |
| 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(std::move(gl)); |
| } |
| |
| MacGLTestContext::~MacGLTestContext() { |
| this->teardown(); |
| this->destroyGLContext(); |
| } |
| |
| void MacGLTestContext::destroyGLContext() { |
| if (fContext) { |
| if (CGLGetCurrentContext() == fContext) { |
| // This will ensure that the context is immediately deleted. |
| CGLSetCurrentContext(nullptr); |
| } |
| CGLReleaseContext(fContext); |
| fContext = nullptr; |
| } |
| if (nullptr != fGLLibrary) { |
| dlclose(fGLLibrary); |
| } |
| } |
| |
| void MacGLTestContext::onPlatformMakeNotCurrent() const { |
| CGLSetCurrentContext(nullptr); |
| } |
| |
| void MacGLTestContext::onPlatformMakeCurrent() const { |
| CGLSetCurrentContext(fContext); |
| } |
| |
| std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const { |
| if (CGLGetCurrentContext() == fContext) { |
| return nullptr; |
| } |
| return context_restorer(); |
| } |
| |
| GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const { |
| void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary; |
| return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName)); |
| } |
| |
| } // anonymous namespace |
| |
| namespace sk_gpu_test { |
| GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI, |
| GLTestContext* shareContext) { |
| if (kGLES_GrGLStandard == forcedGpuAPI) { |
| return nullptr; |
| } |
| MacGLTestContext* macShareContext = reinterpret_cast<MacGLTestContext*>(shareContext); |
| MacGLTestContext* ctx = new MacGLTestContext(macShareContext); |
| if (!ctx->isValid()) { |
| delete ctx; |
| return nullptr; |
| } |
| return ctx; |
| } |
| } // namespace sk_gpu_test |