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 "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h"
11 #include "tools/gpu/gl/GLTestContext.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 kCGLPFAOpenGLProfile,
49 (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
50 kCGLPFADoubleBuffer,
51
52 // eGPU parameters
53 kCGLPFAAllowOfflineRenderers, // Enables e-GPU.
54 kCGLPFANoRecovery, // Disallows software rendering.
55 kCGLPFARendererID, (CGLPixelFormatAttribute)kCGLRendererATIRadeonX4000ID, // Select Radeon
56 (CGLPixelFormatAttribute)NULL
57 };
58 static const int kFirstEGPUParameter = 3;
59 SkASSERT(kCGLPFAAllowOfflineRenderers == attributes[kFirstEGPUParameter]);
60
61 CGLPixelFormatObj pixFormat;
62 GLint npix;
63 CGLChoosePixelFormat(attributes, &pixFormat, &npix);
64
65 if (nullptr == pixFormat) {
66 // Move the NULL-termination up to remove the eGPU parameters and try again
67 attributes[kFirstEGPUParameter] = (CGLPixelFormatAttribute)NULL;
68 CGLChoosePixelFormat(attributes, &pixFormat, &npix);
69 }
70 if (nullptr == pixFormat) {
71 SkDebugf("CGLChoosePixelFormat failed.");
72 return;
73 }
74
75 CGLCreateContext(pixFormat, shareContext ? shareContext->fContext : nullptr, &fContext);
76 CGLReleasePixelFormat(pixFormat);
77
78 if (nullptr == fContext) {
79 SkDebugf("CGLCreateContext failed.");
80 return;
81 }
82
83 SkScopeExit restorer(context_restorer());
84 CGLSetCurrentContext(fContext);
85
86 auto gl = GrGLInterfaces::MakeMac();
87 if (!gl) {
88 SkDebugf("Context could not create GL interface.\n");
89 this->destroyGLContext();
90 return;
91 }
92 if (!gl->validate()) {
93 SkDebugf("Context could not validate GL interface.\n");
94 this->destroyGLContext();
95 return;
96 }
97
98 fGLLibrary = dlopen(
99 "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
100 RTLD_LAZY);
101
102 this->init(std::move(gl));
103 }
104
~MacGLTestContext()105 MacGLTestContext::~MacGLTestContext() {
106 this->teardown();
107 this->destroyGLContext();
108 }
109
destroyGLContext()110 void MacGLTestContext::destroyGLContext() {
111 if (fContext) {
112 if (CGLGetCurrentContext() == fContext) {
113 // This will ensure that the context is immediately deleted.
114 CGLSetCurrentContext(nullptr);
115 }
116 CGLReleaseContext(fContext);
117 fContext = nullptr;
118 }
119 if (nullptr != fGLLibrary) {
120 dlclose(fGLLibrary);
121 }
122 }
123
onPlatformMakeNotCurrent() const124 void MacGLTestContext::onPlatformMakeNotCurrent() const {
125 CGLSetCurrentContext(nullptr);
126 }
127
onPlatformMakeCurrent() const128 void MacGLTestContext::onPlatformMakeCurrent() const {
129 CGLSetCurrentContext(fContext);
130 }
131
onPlatformGetAutoContextRestore() const132 std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const {
133 if (CGLGetCurrentContext() == fContext) {
134 return nullptr;
135 }
136 return context_restorer();
137 }
138
onPlatformGetProcAddress(const char * procName) const139 GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const {
140 void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
141 return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
142 }
143
144 } // anonymous namespace
145
146 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)147 GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
148 GLTestContext* shareContext) {
149 if (kGLES_GrGLStandard == forcedGpuAPI) {
150 return nullptr;
151 }
152 MacGLTestContext* macShareContext = reinterpret_cast<MacGLTestContext*>(shareContext);
153 MacGLTestContext* ctx = new MacGLTestContext(macShareContext);
154 if (!ctx->isValid()) {
155 delete ctx;
156 return nullptr;
157 }
158 return ctx;
159 }
160 } // namespace sk_gpu_test
161