158629291bc145edca8fb303e465c8537bed65314djsollen@google.com
258629291bc145edca8fb303e465c8537bed65314djsollen@google.com/*
358629291bc145edca8fb303e465c8537bed65314djsollen@google.com * Copyright 2011 Google Inc.
458629291bc145edca8fb303e465c8537bed65314djsollen@google.com *
558629291bc145edca8fb303e465c8537bed65314djsollen@google.com * Use of this source code is governed by a BSD-style license that can be
658629291bc145edca8fb303e465c8537bed65314djsollen@google.com * found in the LICENSE file.
758629291bc145edca8fb303e465c8537bed65314djsollen@google.com */
89e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen#include "gl/SkGLContext.h"
958629291bc145edca8fb303e465c8537bed65314djsollen@google.com
109e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen#include <GLES2/gl2.h>
119e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen#include <EGL/egl.h>
1258629291bc145edca8fb303e465c8537bed65314djsollen@google.com
139e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunennamespace {
14a90ed4e83897b45d6331ee4c54e1edd4054de9a8kkinnunen
159e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenclass EGLGLContext : public SkGLContext  {
169e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenpublic:
1730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    EGLGLContext(GrGLStandard forcedGpuAPI);
1836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    ~EGLGLContext() override;
1936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void makeCurrent() const override;
2036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void swapBuffers() const override;
2158629291bc145edca8fb303e465c8537bed65314djsollen@google.com
229e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenprivate:
2330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    void destroyGLContext();
2430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
259e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    EGLContext fContext;
269e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    EGLDisplay fDisplay;
279e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen    EGLSurface fSurface;
289e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen};
2958629291bc145edca8fb303e465c8537bed65314djsollen@google.com
3030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunenEGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI)
3158629291bc145edca8fb303e465c8537bed65314djsollen@google.com    : fContext(EGL_NO_CONTEXT)
3258629291bc145edca8fb303e465c8537bed65314djsollen@google.com    , fDisplay(EGL_NO_DISPLAY)
3358629291bc145edca8fb303e465c8537bed65314djsollen@google.com    , fSurface(EGL_NO_SURFACE) {
34f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org    static const EGLint kEGLContextAttribsForOpenGL[] = {
35f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org        EGL_NONE
36f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org    };
37f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org
38f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org    static const EGLint kEGLContextAttribsForOpenGLES[] = {
39f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org        EGL_CONTEXT_CLIENT_VERSION, 2,
40f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org        EGL_NONE
41f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org    };
42f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org
431e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org    static const struct {
441e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        const EGLint* fContextAttribs;
451e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        EGLenum fAPI;
461e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        EGLint  fRenderableTypeBit;
479e90aed5de82732cc9921f01388d3063a41a053bcommit-bot@chromium.org        GrGLStandard fStandard;
481e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org    } kAPIs[] = {
491e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        {   // OpenGL
501e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            kEGLContextAttribsForOpenGL,
511e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_OPENGL_API,
521e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_OPENGL_BIT,
539e90aed5de82732cc9921f01388d3063a41a053bcommit-bot@chromium.org            kGL_GrGLStandard
541e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        },
551e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
561e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            kEGLContextAttribsForOpenGLES,
571e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_OPENGL_ES_API,
581e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_OPENGL_ES2_BIT,
599e90aed5de82732cc9921f01388d3063a41a053bcommit-bot@chromium.org            kGLES_GrGLStandard
601e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        },
611e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org    };
62f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org
6380549fcdd50269d7e069d6db02b395fca128056ckkinnunen    size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
6480549fcdd50269d7e069d6db02b395fca128056ckkinnunen    size_t api = 0;
6580549fcdd50269d7e069d6db02b395fca128056ckkinnunen    if (forcedGpuAPI == kGL_GrGLStandard) {
6680549fcdd50269d7e069d6db02b395fca128056ckkinnunen        apiLimit = 1;
6780549fcdd50269d7e069d6db02b395fca128056ckkinnunen    } else if (forcedGpuAPI == kGLES_GrGLStandard) {
6880549fcdd50269d7e069d6db02b395fca128056ckkinnunen        api = 1;
6980549fcdd50269d7e069d6db02b395fca128056ckkinnunen    }
7080549fcdd50269d7e069d6db02b395fca128056ckkinnunen    SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
7180549fcdd50269d7e069d6db02b395fca128056ckkinnunen
7230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    for (; NULL == fGL.get() && api < apiLimit; ++api) {
731e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
7458629291bc145edca8fb303e465c8537bed65314djsollen@google.com
751e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        EGLint majorVersion;
761e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        EGLint minorVersion;
771e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        eglInitialize(fDisplay, &majorVersion, &minorVersion);
78dabdd9e71df4619db0260b9091c9bcc0d57b0a34borenet@google.com
791e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org#if 0
801e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
811e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
821e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
831e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
841e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org#endif
8558629291bc145edca8fb303e465c8537bed65314djsollen@google.com
861e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        if (!eglBindAPI(kAPIs[api].fAPI)) {
871e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
881e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
8958629291bc145edca8fb303e465c8537bed65314djsollen@google.com
90bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg        EGLint numConfigs = 0;
911e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        const EGLint configAttribs[] = {
921e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
931e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
941e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_RED_SIZE, 8,
951e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_GREEN_SIZE, 8,
961e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_BLUE_SIZE, 8,
971e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_ALPHA_SIZE, 8,
981e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_NONE
991e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        };
1001e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org
1011e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        EGLConfig surfaceConfig;
1021e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
1031e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
1041e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
1051e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
10658629291bc145edca8fb303e465c8537bed65314djsollen@google.com
107bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg        if (0 == numConfigs) {
108bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg            SkDebugf("No suitable EGL config found.\n");
109bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg            continue;
110bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg        }
111bb25e44593ff9c318d9fe1dbb5cf30bc2b89eb76joakim.landberg
1121e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        fContext = eglCreateContext(fDisplay, surfaceConfig, NULL, kAPIs[api].fContextAttribs);
1131e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        if (EGL_NO_CONTEXT == fContext) {
1141e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
1151e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
1161e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
11758629291bc145edca8fb303e465c8537bed65314djsollen@google.com
1181e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        static const EGLint kSurfaceAttribs[] = {
1191e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_WIDTH, 1,
1201e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_HEIGHT, 1,
1211e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            EGL_NONE
1221e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        };
1231e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org
1241e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
1251e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        if (EGL_NO_SURFACE == fSurface) {
1261e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
1271e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            this->destroyGLContext();
1281e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
1291e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
13058629291bc145edca8fb303e465c8537bed65314djsollen@google.com
1311e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
1321e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
1331e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            this->destroyGLContext();
1341e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
1351e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
13658629291bc145edca8fb303e465c8537bed65314djsollen@google.com
13730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        fGL.reset(GrGLCreateNativeInterface());
13830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (NULL == fGL.get()) {
1391e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            SkDebugf("Failed to create gl interface.\n");
1401e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            this->destroyGLContext();
1411e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            continue;
1421e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
1431e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org
14430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (!fGL->validate()) {
14530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            SkDebugf("Failed to validate gl interface.\n");
1461e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org            this->destroyGLContext();
14730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            continue;
1481e627276c55f1627bef3afa0051685d99443ab1fcommit-bot@chromium.org        }
14958629291bc145edca8fb303e465c8537bed65314djsollen@google.com    }
15030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen}
151f5897f83e65f18a85f71f2d3357df13c5443e89fcommit-bot@chromium.org
15230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunenEGLGLContext::~EGLGLContext() {
15330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    this->destroyGLContext();
15458629291bc145edca8fb303e465c8537bed65314djsollen@google.com}
15558629291bc145edca8fb303e465c8537bed65314djsollen@google.com
15630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunenvoid EGLGLContext::destroyGLContext() {
15730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    fGL.reset(NULL);
15830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    if (fDisplay) {
15930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        eglMakeCurrent(fDisplay, 0, 0, 0);
16030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
16130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (fContext) {
16230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            eglDestroyContext(fDisplay, fContext);
16330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            fContext = EGL_NO_CONTEXT;
16430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        }
16530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
16630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        if (fSurface) {
16730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            eglDestroySurface(fDisplay, fSurface);
16830bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen            fSurface = EGL_NO_SURFACE;
16930bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        }
17030bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
17130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        //TODO should we close the display?
17230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        fDisplay = EGL_NO_DISPLAY;
17330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    }
17430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen}
17530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
17630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen
1779e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenvoid EGLGLContext::makeCurrent() const {
17858629291bc145edca8fb303e465c8537bed65314djsollen@google.com    if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
17958629291bc145edca8fb303e465c8537bed65314djsollen@google.com        SkDebugf("Could not set the context.\n");
18058629291bc145edca8fb303e465c8537bed65314djsollen@google.com    }
18158629291bc145edca8fb303e465c8537bed65314djsollen@google.com}
182c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com
1839e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunenvoid EGLGLContext::swapBuffers() const {
184c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com    if (!eglSwapBuffers(fDisplay, fSurface)) {
185c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com        SkDebugf("Could not complete eglSwapBuffers.\n");
186c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com    }
187c9542ca3d00878a18a57af80037060d6374d5650djsollen@google.com}
1889e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
1899e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen} // anonymous namespace
1909e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
19130bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunenSkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
19230bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    EGLGLContext* ctx = SkNEW_ARGS(EGLGLContext, (forcedGpuAPI));
19330bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    if (!ctx->isValid()) {
19430bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        SkDELETE(ctx);
19530bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen        return NULL;
19630bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    }
19730bc88ccd524c0372fd2f8f79190ea4b81685bebkkinnunen    return ctx;
1989e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen}
1999e61bb7815b133bc40ea7b00fccc853f4b728e3ckkinnunen
200