xref: /aosp_15_r20/external/skia/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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