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 "SkTypes.h"
9
10#include "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 onPlatformMakeCurrent() const override;
32    std::function<void()> onPlatformGetAutoContextRestore() const override;
33    void onPlatformSwapBuffers() 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    CGLPixelFormatAttribute attributes[] = {
44#if MAC_OS_X_VERSION_10_7
45        kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
46#endif
47        kCGLPFADoubleBuffer,
48        (CGLPixelFormatAttribute)0
49    };
50    CGLPixelFormatObj pixFormat;
51    GLint npix;
52
53    CGLChoosePixelFormat(attributes, &pixFormat, &npix);
54
55    if (nullptr == pixFormat) {
56        SkDebugf("CGLChoosePixelFormat failed.");
57        return;
58    }
59
60    CGLCreateContext(pixFormat, shareContext ? shareContext->fContext : nullptr, &fContext);
61    CGLReleasePixelFormat(pixFormat);
62
63    if (nullptr == fContext) {
64        SkDebugf("CGLCreateContext failed.");
65        return;
66    }
67
68    SkScopeExit restorer(context_restorer());
69    CGLSetCurrentContext(fContext);
70
71    auto gl = GrGLMakeNativeInterface();
72    if (!gl) {
73        SkDebugf("Context could not create GL interface.\n");
74        this->destroyGLContext();
75        return;
76    }
77    if (!gl->validate()) {
78        SkDebugf("Context could not validate GL interface.\n");
79        this->destroyGLContext();
80        return;
81    }
82
83    fGLLibrary = dlopen(
84        "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
85        RTLD_LAZY);
86
87    this->init(std::move(gl));
88}
89
90MacGLTestContext::~MacGLTestContext() {
91    this->teardown();
92    this->destroyGLContext();
93}
94
95void MacGLTestContext::destroyGLContext() {
96    if (fContext) {
97        if (CGLGetCurrentContext() == fContext) {
98            // This will ensure that the context is immediately deleted.
99            CGLSetCurrentContext(nullptr);
100        }
101        CGLReleaseContext(fContext);
102        fContext = nullptr;
103    }
104    if (nullptr != fGLLibrary) {
105        dlclose(fGLLibrary);
106    }
107}
108
109void MacGLTestContext::onPlatformMakeCurrent() const {
110    CGLSetCurrentContext(fContext);
111}
112
113std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const {
114    if (CGLGetCurrentContext() == fContext) {
115        return nullptr;
116    }
117    return context_restorer();
118}
119
120void MacGLTestContext::onPlatformSwapBuffers() const {
121    CGLFlushDrawable(fContext);
122}
123
124GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const {
125    void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
126    return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
127}
128
129}  // anonymous namespace
130
131namespace sk_gpu_test {
132GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
133                                           GLTestContext* shareContext) {
134    if (kGLES_GrGLStandard == forcedGpuAPI) {
135        return nullptr;
136    }
137    MacGLTestContext* macShareContext = reinterpret_cast<MacGLTestContext*>(shareContext);
138    MacGLTestContext* ctx = new MacGLTestContext(macShareContext);
139    if (!ctx->isValid()) {
140        delete ctx;
141        return nullptr;
142    }
143    return ctx;
144}
145}  // namespace sk_gpu_test
146