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 "../GLWindowContext.h"
12#include "WindowContextFactory_android.h"
13#include "gl/GrGLInterface.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    typedef GLWindowContext INHERITED;
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    // These values are the same as the corresponding VG colorspace attributes,
105    // which were accepted starting in EGL 1.2. For some reason in 1.4, sRGB
106    // became hidden behind an extension, but it looks like devices aren't
107    // advertising that extension (including Nexus 5X). So just check version?
108    const EGLint srgbWindowAttribs[] = {
109        /*EGL_GL_COLORSPACE_KHR*/ 0x309D, /*EGL_GL_COLORSPACE_SRGB_KHR*/ 0x3089,
110        EGL_NONE,
111    };
112    const EGLint* windowAttribs = nullptr;
113    auto srgbColorSpace = SkColorSpace::MakeSRGB();
114    if (srgbColorSpace == fDisplayParams.fColorSpace && majorVersion == 1 && minorVersion >= 2) {
115        windowAttribs = srgbWindowAttribs;
116    }
117
118    fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, windowAttribs);
119    if (EGL_NO_SURFACE == fSurfaceAndroid && windowAttribs) {
120        // Try again without sRGB
121        fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, nullptr);
122    }
123    SkASSERT(EGL_NO_SURFACE != fSurfaceAndroid);
124
125    SkAssertResult(eglMakeCurrent(fDisplay, fSurfaceAndroid, fSurfaceAndroid, fEGLContext));
126    // GLWindowContext::initializeContext will call GrGLMakeNativeInterface so we
127    // won't call it here.
128
129    glClearStencil(0);
130    glClearColor(0, 0, 0, 0);
131    glStencilMask(0xffffffff);
132    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
133
134    eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &fStencilBits);
135    eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &fSampleCount);
136    fSampleCount = SkTMax(fSampleCount, 1);
137
138    return GrGLMakeNativeInterface();
139}
140
141void GLWindowContext_android::onDestroyContext() {
142    if (!fDisplay || !fEGLContext || !fSurfaceAndroid) {
143        return;
144    }
145    eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
146    SkAssertResult(eglDestroySurface(fDisplay, fSurfaceAndroid));
147    SkAssertResult(eglDestroyContext(fDisplay, fEGLContext));
148    fEGLContext = EGL_NO_CONTEXT;
149    fSurfaceAndroid = EGL_NO_SURFACE;
150}
151
152void GLWindowContext_android::onSwapBuffers() {
153    if (fDisplay && fEGLContext && fSurfaceAndroid) {
154        eglSwapBuffers(fDisplay, fSurfaceAndroid);
155    }
156}
157
158}  // anonymous namespace
159
160namespace sk_app {
161namespace window_context_factory {
162
163WindowContext* NewGLForAndroid(ANativeWindow* window, const DisplayParams& params) {
164    WindowContext* ctx = new GLWindowContext_android(window, params);
165    if (!ctx->isValid()) {
166        delete ctx;
167        return nullptr;
168    }
169    return ctx;
170}
171
172}  // namespace window_context_factory
173}  // namespace sk_app
174