1 2/* 3 * Copyright 2011 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 "include/core/SkTypes.h" 9 10#include "tools/gpu/gl/GLTestContext.h" 11#include "AvailabilityMacros.h" 12 13#include <OpenGL/OpenGL.h> 14#include <dlfcn.h> 15 16namespace { 17 18std::function<void()> context_restorer() { 19 auto context = CGLGetCurrentContext(); 20 return [context] { CGLSetCurrentContext(context); }; 21} 22 23class MacGLTestContext : public sk_gpu_test::GLTestContext { 24public: 25 MacGLTestContext(MacGLTestContext* shareContext); 26 ~MacGLTestContext() override; 27 28private: 29 void destroyGLContext(); 30 31 void onPlatformMakeNotCurrent() const override; 32 void onPlatformMakeCurrent() const override; 33 std::function<void()> onPlatformGetAutoContextRestore() const override; 34 GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; 35 36 CGLContextObj fContext; 37 void* fGLLibrary; 38}; 39 40MacGLTestContext::MacGLTestContext(MacGLTestContext* shareContext) 41 : fContext(nullptr) 42 , fGLLibrary(RTLD_DEFAULT) { 43 // We first try to request a Radeon eGPU if one is available. 44 // This will be a Radeon HD7000 and up, which includes all eGPU configs. 45 // If that fails, we try again with only the base parameters. 46 CGLPixelFormatAttribute attributes[] = { 47 // base parameters 48#if MAC_OS_X_VERSION_10_7 49 kCGLPFAOpenGLProfile, 50 (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core, 51#endif 52 kCGLPFADoubleBuffer, 53 54#if MAC_OS_X_VERSION_10_8 55 // eGPU parameters 56 kCGLPFAAllowOfflineRenderers, // Enables e-GPU. 57 kCGLPFANoRecovery, // Disallows software rendering. 58 kCGLPFARendererID, (CGLPixelFormatAttribute)kCGLRendererATIRadeonX4000ID, // Select Radeon 59#endif 60 (CGLPixelFormatAttribute)NULL 61 }; 62#if MAC_OS_X_VERSION_10_8 63 static const int kFirstEGPUParameter = 3; 64 SkASSERT(kCGLPFAAllowOfflineRenderers == attributes[kFirstEGPUParameter]); 65#endif 66 67 CGLPixelFormatObj pixFormat; 68 GLint npix; 69 CGLChoosePixelFormat(attributes, &pixFormat, &npix); 70 71#if MAC_OS_X_VERSION_10_8 72 if (nullptr == pixFormat) { 73 // Move the NULL-termination up to remove the eGPU parameters and try again 74 attributes[kFirstEGPUParameter] = (CGLPixelFormatAttribute)NULL; 75 CGLChoosePixelFormat(attributes, &pixFormat, &npix); 76 } 77#endif 78 if (nullptr == pixFormat) { 79 SkDebugf("CGLChoosePixelFormat failed."); 80 return; 81 } 82 83 CGLCreateContext(pixFormat, shareContext ? shareContext->fContext : nullptr, &fContext); 84 CGLReleasePixelFormat(pixFormat); 85 86 if (nullptr == fContext) { 87 SkDebugf("CGLCreateContext failed."); 88 return; 89 } 90 91 SkScopeExit restorer(context_restorer()); 92 CGLSetCurrentContext(fContext); 93 94 auto gl = GrGLMakeNativeInterface(); 95 if (!gl) { 96 SkDebugf("Context could not create GL interface.\n"); 97 this->destroyGLContext(); 98 return; 99 } 100 if (!gl->validate()) { 101 SkDebugf("Context could not validate GL interface.\n"); 102 this->destroyGLContext(); 103 return; 104 } 105 106 fGLLibrary = dlopen( 107 "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", 108 RTLD_LAZY); 109 110 this->init(std::move(gl)); 111} 112 113MacGLTestContext::~MacGLTestContext() { 114 this->teardown(); 115 this->destroyGLContext(); 116} 117 118void MacGLTestContext::destroyGLContext() { 119 if (fContext) { 120 if (CGLGetCurrentContext() == fContext) { 121 // This will ensure that the context is immediately deleted. 122 CGLSetCurrentContext(nullptr); 123 } 124 CGLReleaseContext(fContext); 125 fContext = nullptr; 126 } 127 if (nullptr != fGLLibrary) { 128 dlclose(fGLLibrary); 129 } 130} 131 132void MacGLTestContext::onPlatformMakeNotCurrent() const { 133 CGLSetCurrentContext(nullptr); 134} 135 136void MacGLTestContext::onPlatformMakeCurrent() const { 137 CGLSetCurrentContext(fContext); 138} 139 140std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const { 141 if (CGLGetCurrentContext() == fContext) { 142 return nullptr; 143 } 144 return context_restorer(); 145} 146 147GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const { 148 void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary; 149 return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName)); 150} 151 152} // anonymous namespace 153 154namespace sk_gpu_test { 155GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI, 156 GLTestContext* shareContext) { 157 if (kGLES_GrGLStandard == forcedGpuAPI) { 158 return nullptr; 159 } 160 MacGLTestContext* macShareContext = reinterpret_cast<MacGLTestContext*>(shareContext); 161 MacGLTestContext* ctx = new MacGLTestContext(macShareContext); 162 if (!ctx->isValid()) { 163 delete ctx; 164 return nullptr; 165 } 166 return ctx; 167} 168} // namespace sk_gpu_test 169