1
2/*
3 * Copyright 2016 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 <EGL/egl.h>
10#include <GLES/gl.h>
11#include "include/gpu/gl/GrGLInterface.h"
12#include "tools/sk_app/GLWindowContext.h"
13#include "tools/sk_app/android/WindowContextFactory_android.h"
14
15using sk_app::GLWindowContext;
16using sk_app::DisplayParams;
17
18namespace {
19class GLWindowContext_android : public GLWindowContext {
20public:
21
22    GLWindowContext_android(ANativeWindow*, const DisplayParams&);
23
24    ~GLWindowContext_android() override;
25
26    void onSwapBuffers() override;
27
28    sk_sp<const GrGLInterface> onInitializeContext() override;
29    void onDestroyContext() override;
30
31private:
32
33    EGLDisplay fDisplay;
34    EGLContext fEGLContext;
35    EGLSurface fSurfaceAndroid;
36
37    // For setDisplayParams and resize which call onInitializeContext with null platformData
38    ANativeWindow* fNativeWindow = nullptr;
39
40    using INHERITED = GLWindowContext;
41};
42
43GLWindowContext_android::GLWindowContext_android(ANativeWindow* window,
44                                                 const DisplayParams& params)
45    : INHERITED(params)
46    , fDisplay(EGL_NO_DISPLAY)
47    , fEGLContext(EGL_NO_CONTEXT)
48    , fSurfaceAndroid(EGL_NO_SURFACE)
49    , fNativeWindow(window) {
50
51    // any config code here (particularly for msaa)?
52
53    this->initializeContext();
54}
55
56GLWindowContext_android::~GLWindowContext_android() {
57    this->destroyContext();
58}
59
60sk_sp<const GrGLInterface> GLWindowContext_android::onInitializeContext() {
61    fWidth = ANativeWindow_getWidth(fNativeWindow);
62    fHeight = ANativeWindow_getHeight(fNativeWindow);
63
64    fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
65
66    EGLint majorVersion;
67    EGLint minorVersion;
68    eglInitialize(fDisplay, &majorVersion, &minorVersion);
69
70    SkAssertResult(eglBindAPI(EGL_OPENGL_ES_API));
71
72    EGLint numConfigs = 0;
73    EGLint eglSampleCnt = fDisplayParams.fMSAASampleCount > 1 ? fDisplayParams.fMSAASampleCount > 1
74                                                              : 0;
75    const EGLint configAttribs[] = {
76        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
77        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
78        EGL_RED_SIZE, 8,
79        EGL_GREEN_SIZE, 8,
80        EGL_BLUE_SIZE, 8,
81        EGL_ALPHA_SIZE, 8,
82        EGL_STENCIL_SIZE, 8,
83        EGL_SAMPLE_BUFFERS, eglSampleCnt ? 1 : 0,
84        EGL_SAMPLES, eglSampleCnt,
85        EGL_NONE
86    };
87
88    EGLConfig surfaceConfig;
89    SkAssertResult(eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs));
90    SkASSERT(numConfigs > 0);
91
92    static const EGLint kEGLContextAttribsForOpenGLES[] = {
93        EGL_CONTEXT_CLIENT_VERSION, 2,
94        EGL_NONE
95    };
96    fEGLContext = eglCreateContext(
97            fDisplay, surfaceConfig, nullptr, kEGLContextAttribsForOpenGLES);
98    SkASSERT(EGL_NO_CONTEXT != fEGLContext);
99
100//    SkDebugf("EGL: %d.%d", majorVersion, minorVersion);
101//    SkDebugf("Vendor: %s", eglQueryString(fDisplay, EGL_VENDOR));
102//    SkDebugf("Extensions: %s", eglQueryString(fDisplay, EGL_EXTENSIONS));
103
104    fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, nullptr);
105    SkASSERT(EGL_NO_SURFACE != fSurfaceAndroid);
106
107    SkAssertResult(eglMakeCurrent(fDisplay, fSurfaceAndroid, fSurfaceAndroid, fEGLContext));
108    // GLWindowContext::initializeContext will call GrGLMakeNativeInterface so we
109    // won't call it here.
110
111    glClearStencil(0);
112    glClearColor(0, 0, 0, 0);
113    glStencilMask(0xffffffff);
114    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
115
116    eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &fStencilBits);
117    eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &fSampleCount);
118    fSampleCount = std::max(fSampleCount, 1);
119
120    eglSwapInterval(fDisplay, fDisplayParams.fDisableVsync ? 0 : 1);
121
122    return GrGLMakeNativeInterface();
123}
124
125void GLWindowContext_android::onDestroyContext() {
126    if (!fDisplay || !fEGLContext || !fSurfaceAndroid) {
127        return;
128    }
129    eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
130    SkAssertResult(eglDestroySurface(fDisplay, fSurfaceAndroid));
131    SkAssertResult(eglDestroyContext(fDisplay, fEGLContext));
132    fEGLContext = EGL_NO_CONTEXT;
133    fSurfaceAndroid = EGL_NO_SURFACE;
134}
135
136void GLWindowContext_android::onSwapBuffers() {
137    if (fDisplay && fEGLContext && fSurfaceAndroid) {
138        eglSwapBuffers(fDisplay, fSurfaceAndroid);
139    }
140}
141
142}  // anonymous namespace
143
144namespace sk_app {
145namespace window_context_factory {
146
147std::unique_ptr<WindowContext> MakeGLForAndroid(ANativeWindow* window,
148                                                const DisplayParams& params) {
149    std::unique_ptr<WindowContext> ctx(new GLWindowContext_android(window, params));
150    if (!ctx->isValid()) {
151        return nullptr;
152    }
153    return ctx;
154}
155
156}  // namespace window_context_factory
157}  // namespace sk_app
158