1
2/*
3 * Copyright 2012 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
9#include "gl/GLTestContext.h"
10#import <OpenGLES/EAGL.h>
11#include <dlfcn.h>
12
13#define EAGLCTX ((EAGLContext*)(fEAGLContext))
14
15namespace {
16
17std::function<void()> context_restorer() {
18    EAGLContext* context = [EAGLContext currentContext];
19    return [context] { [EAGLContext setCurrentContext:context]; };
20}
21
22class IOSGLTestContext : public sk_gpu_test::GLTestContext {
23public:
24    IOSGLTestContext(IOSGLTestContext* shareContext);
25    ~IOSGLTestContext() override;
26
27private:
28    void destroyGLContext();
29
30    void onPlatformMakeCurrent() const override;
31    std::function<void()> onPlatformGetAutoContextRestore() const override;
32    void onPlatformSwapBuffers() const override;
33    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
34
35    EAGLContext* fEAGLContext;
36    void* fGLLibrary;
37};
38
39IOSGLTestContext::IOSGLTestContext(IOSGLTestContext* shareContext)
40    : fEAGLContext(NULL)
41    , fGLLibrary(RTLD_DEFAULT) {
42
43    if (shareContext) {
44        EAGLContext* iosShareContext = shareContext->fEAGLContext;
45        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
46                                            sharegroup:[iosShareContext sharegroup]];
47        if (fEAGLContext == nil) {
48            fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2
49                                                sharegroup:[iosShareContext sharegroup]];
50        }
51    } else {
52        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
53        if (fEAGLContext == nil) {
54            fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
55        }
56    }
57    SkScopeExit restorer(context_restorer());
58    [EAGLContext setCurrentContext:fEAGLContext];
59
60    sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
61    if (NULL == gl.get()) {
62        SkDebugf("Failed to create gl interface");
63        this->destroyGLContext();
64        return;
65    }
66    if (!gl->validate()) {
67        SkDebugf("Failed to validate gl interface");
68        this->destroyGLContext();
69        return;
70    }
71
72    fGLLibrary = dlopen(
73        "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
74        RTLD_LAZY);
75
76    this->init(std::move(gl));
77}
78
79IOSGLTestContext::~IOSGLTestContext() {
80    this->teardown();
81    this->destroyGLContext();
82}
83
84void IOSGLTestContext::destroyGLContext() {
85    if (fEAGLContext) {
86        if ([EAGLContext currentContext] == fEAGLContext) {
87            // This will ensure that the context is immediately deleted.
88            [EAGLContext setCurrentContext:nil];
89        }
90        fEAGLContext = nil;
91    }
92    if (nullptr != fGLLibrary) {
93        dlclose(fGLLibrary);
94    }
95}
96
97
98void IOSGLTestContext::onPlatformMakeCurrent() const {
99    if (![EAGLContext setCurrentContext:fEAGLContext]) {
100        SkDebugf("Could not set the context.\n");
101    }
102}
103
104std::function<void()> IOSGLTestContext::onPlatformGetAutoContextRestore() const {
105    if ([EAGLContext currentContext] == fEAGLContext) {
106		return nullptr;
107	}
108    return context_restorer();
109}
110
111void IOSGLTestContext::onPlatformSwapBuffers() const { }
112
113GrGLFuncPtr IOSGLTestContext::onPlatformGetProcAddress(const char* procName) const {
114    void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
115    return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
116}
117
118}  // anonymous namespace
119
120namespace sk_gpu_test {
121GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
122                                           GLTestContext *shareContext) {
123    if (kGL_GrGLStandard == forcedGpuAPI) {
124        return NULL;
125    }
126    IOSGLTestContext* iosShareContext = reinterpret_cast<IOSGLTestContext*>(shareContext);
127    IOSGLTestContext *ctx = new IOSGLTestContext(iosShareContext);
128    if (!ctx->isValid()) {
129        delete ctx;
130        return NULL;
131    }
132    return ctx;
133}
134}
135