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
16 namespace {
17
context_restorer()18 std::function<void()> context_restorer() {
19 auto context = CGLGetCurrentContext();
20 return [context] { CGLSetCurrentContext(context); };
21 }
22
23 class MacGLTestContext : public sk_gpu_test::GLTestContext {
24 public:
25 MacGLTestContext(MacGLTestContext* shareContext);
26 ~MacGLTestContext() override;
27
28 private:
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
MacGLTestContext(MacGLTestContext * shareContext)40 MacGLTestContext::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
~MacGLTestContext()113 MacGLTestContext::~MacGLTestContext() {
114 this->teardown();
115 this->destroyGLContext();
116 }
117
destroyGLContext()118 void 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
onPlatformMakeNotCurrent() const132 void MacGLTestContext::onPlatformMakeNotCurrent() const {
133 CGLSetCurrentContext(nullptr);
134 }
135
onPlatformMakeCurrent() const136 void MacGLTestContext::onPlatformMakeCurrent() const {
137 CGLSetCurrentContext(fContext);
138 }
139
onPlatformGetAutoContextRestore() const140 std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const {
141 if (CGLGetCurrentContext() == fContext) {
142 return nullptr;
143 }
144 return context_restorer();
145 }
146
onPlatformGetProcAddress(const char * procName) const147 GrGLFuncPtr 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
154 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)155 GLTestContext* 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