Home | History | Annotate | Download | only in egl
      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 "gl/GLTestContext.h"
      9 
     10 #define GL_GLEXT_PROTOTYPES
     11 #include <GLES2/gl2.h>
     12 
     13 #include <EGL/egl.h>
     14 #include <EGL/eglext.h>
     15 
     16 #include "gl/GrGLDefines.h"
     17 #include "gl/GrGLUtil.h"
     18 
     19 namespace {
     20 
     21 // TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
     22 class EGLFenceSync : public sk_gpu_test::FenceSync {
     23 public:
     24     static std::unique_ptr<EGLFenceSync> MakeIfSupported(EGLDisplay);
     25 
     26     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
     27     bool waitFence(sk_gpu_test::PlatformFence fence) const override;
     28     void deleteFence(sk_gpu_test::PlatformFence fence) const override;
     29 
     30 private:
     31     EGLFenceSync(EGLDisplay display);
     32 
     33     PFNEGLCREATESYNCKHRPROC       fEGLCreateSyncKHR;
     34     PFNEGLCLIENTWAITSYNCKHRPROC   fEGLClientWaitSyncKHR;
     35     PFNEGLDESTROYSYNCKHRPROC      fEGLDestroySyncKHR;
     36 
     37     EGLDisplay                    fDisplay;
     38 
     39     typedef sk_gpu_test::FenceSync INHERITED;
     40 };
     41 
     42 std::function<void()> context_restorer() {
     43     auto display = eglGetCurrentDisplay();
     44     auto dsurface = eglGetCurrentSurface(EGL_DRAW);
     45     auto rsurface = eglGetCurrentSurface(EGL_READ);
     46     auto context = eglGetCurrentContext();
     47     return [display, dsurface, rsurface, context] {
     48         eglMakeCurrent(display, dsurface, rsurface, context);
     49     };
     50 }
     51 
     52 class EGLGLTestContext : public sk_gpu_test::GLTestContext {
     53 public:
     54     EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext);
     55     ~EGLGLTestContext() override;
     56 
     57     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
     58     void destroyEGLImage(GrEGLImage) const override;
     59     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
     60     std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
     61 
     62 private:
     63     void destroyGLContext();
     64 
     65     void onPlatformMakeCurrent() const override;
     66     std::function<void()> onPlatformGetAutoContextRestore() const override;
     67     void onPlatformSwapBuffers() const override;
     68     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
     69 
     70     EGLContext fContext;
     71     EGLDisplay fDisplay;
     72     EGLSurface fSurface;
     73 };
     74 
     75 static EGLContext create_gles_egl_context(EGLDisplay display,
     76                                           EGLConfig surfaceConfig,
     77                                           EGLContext eglShareContext,
     78                                           EGLint eglContextClientVersion) {
     79     const EGLint contextAttribsForOpenGLES[] = {
     80         EGL_CONTEXT_CLIENT_VERSION,
     81         eglContextClientVersion,
     82         EGL_NONE
     83     };
     84     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
     85 }
     86 static EGLContext create_gl_egl_context(EGLDisplay display,
     87                                         EGLConfig surfaceConfig,
     88                                         EGLContext eglShareContext) {
     89     const EGLint contextAttribsForOpenGL[] = {
     90         EGL_NONE
     91     };
     92     return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
     93 }
     94 
     95 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
     96     : fContext(EGL_NO_CONTEXT)
     97     , fDisplay(EGL_NO_DISPLAY)
     98     , fSurface(EGL_NO_SURFACE) {
     99 
    100     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
    101 
    102     static const GrGLStandard kStandards[] = {
    103         kGL_GrGLStandard,
    104         kGLES_GrGLStandard,
    105     };
    106 
    107     size_t apiLimit = SK_ARRAY_COUNT(kStandards);
    108     size_t api = 0;
    109     if (forcedGpuAPI == kGL_GrGLStandard) {
    110         apiLimit = 1;
    111     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
    112         api = 1;
    113     }
    114     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
    115 
    116     sk_sp<const GrGLInterface> gl;
    117 
    118     for (; nullptr == gl.get() && api < apiLimit; ++api) {
    119         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    120 
    121         EGLint majorVersion;
    122         EGLint minorVersion;
    123         eglInitialize(fDisplay, &majorVersion, &minorVersion);
    124 
    125 #if 0
    126         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
    127         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
    128         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
    129         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
    130 #endif
    131         bool gles = kGLES_GrGLStandard == kStandards[api];
    132 
    133         if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
    134             continue;
    135         }
    136 
    137         EGLint numConfigs = 0;
    138         const EGLint configAttribs[] = {
    139             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    140             EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
    141             EGL_RED_SIZE, 8,
    142             EGL_GREEN_SIZE, 8,
    143             EGL_BLUE_SIZE, 8,
    144             EGL_ALPHA_SIZE, 8,
    145             EGL_NONE
    146         };
    147 
    148         EGLConfig surfaceConfig;
    149         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
    150             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
    151             continue;
    152         }
    153 
    154         if (0 == numConfigs) {
    155             SkDebugf("No suitable EGL config found.\n");
    156             continue;
    157         }
    158 
    159         if (gles) {
    160 #ifdef GR_EGL_TRY_GLES3_THEN_GLES2
    161             // Some older devices (Nexus7/Tegra3) crash when you try this.  So it is (for now)
    162             // hidden behind this flag.
    163             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
    164             if (EGL_NO_CONTEXT == fContext) {
    165                 fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
    166             }
    167 #else
    168             fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
    169 #endif
    170         } else {
    171             fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
    172         }
    173         if (EGL_NO_CONTEXT == fContext) {
    174             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
    175             continue;
    176         }
    177 
    178         static const EGLint kSurfaceAttribs[] = {
    179             EGL_WIDTH, 1,
    180             EGL_HEIGHT, 1,
    181             EGL_NONE
    182         };
    183 
    184         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
    185         if (EGL_NO_SURFACE == fSurface) {
    186             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
    187             this->destroyGLContext();
    188             continue;
    189         }
    190 
    191         SkScopeExit restorer(context_restorer());
    192         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    193             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
    194             this->destroyGLContext();
    195             continue;
    196         }
    197 
    198         gl = GrGLMakeNativeInterface();
    199         if (!gl) {
    200             SkDebugf("Failed to create gl interface.\n");
    201             this->destroyGLContext();
    202             continue;
    203         }
    204 
    205         if (!gl->validate()) {
    206             SkDebugf("Failed to validate gl interface.\n");
    207             this->destroyGLContext();
    208             continue;
    209         }
    210 
    211         this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
    212         break;
    213     }
    214 }
    215 
    216 EGLGLTestContext::~EGLGLTestContext() {
    217     this->teardown();
    218     this->destroyGLContext();
    219 }
    220 
    221 void EGLGLTestContext::destroyGLContext() {
    222     if (fDisplay) {
    223         if (fContext) {
    224             if (eglGetCurrentContext() == fContext) {
    225                 // This will ensure that the context is immediately deleted.
    226                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    227             }
    228             eglDestroyContext(fDisplay, fContext);
    229             fContext = EGL_NO_CONTEXT;
    230         }
    231 
    232         if (fSurface) {
    233             eglDestroySurface(fDisplay, fSurface);
    234             fSurface = EGL_NO_SURFACE;
    235         }
    236 
    237         //TODO should we close the display?
    238         fDisplay = EGL_NO_DISPLAY;
    239     }
    240 }
    241 
    242 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
    243     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
    244         return GR_EGL_NO_IMAGE;
    245     }
    246     GrEGLImage img;
    247     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
    248     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
    249     GR_GL_CALL_RET(this->gl(), img,
    250                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
    251     return img;
    252 }
    253 
    254 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
    255     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
    256 }
    257 
    258 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
    259     GrGLClearErr(this->gl());
    260     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
    261         return 0;
    262     }
    263     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
    264 
    265     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
    266         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
    267     if (!glEGLImageTargetTexture2D) {
    268         return 0;
    269     }
    270     GrGLuint texID;
    271     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
    272     if (!texID) {
    273         return 0;
    274     }
    275     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
    276     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    277         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    278         return 0;
    279     }
    280     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
    281     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    282         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    283         return 0;
    284     }
    285     return texID;
    286 }
    287 
    288 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
    289     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
    290                                                                          nullptr));
    291     if (ctx) {
    292         ctx->makeCurrent();
    293     }
    294     return ctx;
    295 }
    296 
    297 void EGLGLTestContext::onPlatformMakeCurrent() const {
    298     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    299         SkDebugf("Could not set the context.\n");
    300     }
    301 }
    302 
    303 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
    304     if (eglGetCurrentContext() == fContext) {
    305         return nullptr;
    306     }
    307     return context_restorer();
    308 }
    309 
    310 void EGLGLTestContext::onPlatformSwapBuffers() const {
    311     if (!eglSwapBuffers(fDisplay, fSurface)) {
    312         SkDebugf("Could not complete eglSwapBuffers.\n");
    313     }
    314 }
    315 
    316 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
    317     return eglGetProcAddress(procName);
    318 }
    319 
    320 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
    321     size_t extensionLength = strlen(extension);
    322     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
    323     while (const char* match = strstr(extensionsStr, extension)) {
    324         // Ensure the string we found is its own extension, not a substring of a larger extension
    325         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
    326         if ((match == extensionsStr || match[-1] == ' ') &&
    327             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
    328             return true;
    329         }
    330         extensionsStr = match + extensionLength;
    331     }
    332     return false;
    333 }
    334 
    335 std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
    336     if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
    337         return nullptr;
    338     }
    339     return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
    340 }
    341 
    342 EGLFenceSync::EGLFenceSync(EGLDisplay display)
    343     : fDisplay(display) {
    344     fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
    345     fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
    346     fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
    347     SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
    348 }
    349 
    350 sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
    351     EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
    352     return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
    353 }
    354 
    355 bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
    356     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
    357     return EGL_CONDITION_SATISFIED_KHR ==
    358             fEGLClientWaitSyncKHR(fDisplay,
    359                                   eglsync,
    360                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
    361                                   EGL_FOREVER_KHR);
    362 }
    363 
    364 void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
    365     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
    366     fEGLDestroySyncKHR(fDisplay, eglsync);
    367 }
    368 
    369 GR_STATIC_ASSERT(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
    370 
    371 }  // anonymous namespace
    372 
    373 namespace sk_gpu_test {
    374 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
    375                                            GLTestContext *shareContext) {
    376     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
    377     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
    378     if (!ctx->isValid()) {
    379         delete ctx;
    380         return nullptr;
    381     }
    382     return ctx;
    383 }
    384 }  // namespace sk_gpu_test
    385