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 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
     76     : fContext(EGL_NO_CONTEXT)
     77     , fDisplay(EGL_NO_DISPLAY)
     78     , fSurface(EGL_NO_SURFACE) {
     79 
     80     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
     81 
     82     static const EGLint kEGLContextAttribsForOpenGL[] = {
     83         EGL_NONE
     84     };
     85 
     86     static const EGLint kEGLContextAttribsForOpenGLES[] = {
     87         EGL_CONTEXT_CLIENT_VERSION, 2,
     88         EGL_NONE
     89     };
     90 
     91     static const struct {
     92         const EGLint* fContextAttribs;
     93         EGLenum fAPI;
     94         EGLint  fRenderableTypeBit;
     95         GrGLStandard fStandard;
     96     } kAPIs[] = {
     97         {   // OpenGL
     98             kEGLContextAttribsForOpenGL,
     99             EGL_OPENGL_API,
    100             EGL_OPENGL_BIT,
    101             kGL_GrGLStandard
    102         },
    103         {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
    104             kEGLContextAttribsForOpenGLES,
    105             EGL_OPENGL_ES_API,
    106             EGL_OPENGL_ES2_BIT,
    107             kGLES_GrGLStandard
    108         },
    109     };
    110 
    111     size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
    112     size_t api = 0;
    113     if (forcedGpuAPI == kGL_GrGLStandard) {
    114         apiLimit = 1;
    115     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
    116         api = 1;
    117     }
    118     SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
    119 
    120     sk_sp<const GrGLInterface> gl;
    121 
    122     for (; nullptr == gl.get() && api < apiLimit; ++api) {
    123         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    124 
    125         EGLint majorVersion;
    126         EGLint minorVersion;
    127         eglInitialize(fDisplay, &majorVersion, &minorVersion);
    128 
    129 #if 0
    130         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
    131         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
    132         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
    133         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
    134 #endif
    135 
    136         if (!eglBindAPI(kAPIs[api].fAPI)) {
    137             continue;
    138         }
    139 
    140         EGLint numConfigs = 0;
    141         const EGLint configAttribs[] = {
    142             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    143             EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
    144             EGL_RED_SIZE, 8,
    145             EGL_GREEN_SIZE, 8,
    146             EGL_BLUE_SIZE, 8,
    147             EGL_ALPHA_SIZE, 8,
    148             EGL_NONE
    149         };
    150 
    151         EGLConfig surfaceConfig;
    152         if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
    153             SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
    154             continue;
    155         }
    156 
    157         if (0 == numConfigs) {
    158             SkDebugf("No suitable EGL config found.\n");
    159             continue;
    160         }
    161 
    162         fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext,
    163                                     kAPIs[api].fContextAttribs);
    164         if (EGL_NO_CONTEXT == fContext) {
    165             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
    166             continue;
    167         }
    168 
    169         static const EGLint kSurfaceAttribs[] = {
    170             EGL_WIDTH, 1,
    171             EGL_HEIGHT, 1,
    172             EGL_NONE
    173         };
    174 
    175         fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
    176         if (EGL_NO_SURFACE == fSurface) {
    177             SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
    178             this->destroyGLContext();
    179             continue;
    180         }
    181 
    182         SkScopeExit restorer(context_restorer());
    183         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    184             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
    185             this->destroyGLContext();
    186             continue;
    187         }
    188 
    189         gl = GrGLMakeNativeInterface();
    190         if (!gl) {
    191             SkDebugf("Failed to create gl interface.\n");
    192             this->destroyGLContext();
    193             continue;
    194         }
    195 
    196         if (!gl->validate()) {
    197             SkDebugf("Failed to validate gl interface.\n");
    198             this->destroyGLContext();
    199             continue;
    200         }
    201 
    202         this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
    203         break;
    204     }
    205 }
    206 
    207 EGLGLTestContext::~EGLGLTestContext() {
    208     this->teardown();
    209     this->destroyGLContext();
    210 }
    211 
    212 void EGLGLTestContext::destroyGLContext() {
    213     if (fDisplay) {
    214         if (fContext) {
    215             if (eglGetCurrentContext() == fContext) {
    216                 // This will ensure that the context is immediately deleted.
    217                 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    218             }
    219             eglDestroyContext(fDisplay, fContext);
    220             fContext = EGL_NO_CONTEXT;
    221         }
    222 
    223         if (fSurface) {
    224             eglDestroySurface(fDisplay, fSurface);
    225             fSurface = EGL_NO_SURFACE;
    226         }
    227 
    228         //TODO should we close the display?
    229         fDisplay = EGL_NO_DISPLAY;
    230     }
    231 }
    232 
    233 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
    234     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
    235         return GR_EGL_NO_IMAGE;
    236     }
    237     GrEGLImage img;
    238     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
    239     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
    240     GR_GL_CALL_RET(this->gl(), img,
    241                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
    242     return img;
    243 }
    244 
    245 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
    246     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
    247 }
    248 
    249 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
    250     GrGLClearErr(this->gl());
    251     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
    252         return 0;
    253     }
    254     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
    255 
    256     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
    257         (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
    258     if (!glEGLImageTargetTexture2D) {
    259         return 0;
    260     }
    261     GrGLuint texID;
    262     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
    263     if (!texID) {
    264         return 0;
    265     }
    266     GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
    267     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    268         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    269         return 0;
    270     }
    271     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
    272     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    273         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    274         return 0;
    275     }
    276     return texID;
    277 }
    278 
    279 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
    280     std::unique_ptr<sk_gpu_test::GLTestContext> ctx(new EGLGLTestContext(this->gl()->fStandard,
    281                                                                          nullptr));
    282     if (ctx) {
    283         ctx->makeCurrent();
    284     }
    285     return ctx;
    286 }
    287 
    288 void EGLGLTestContext::onPlatformMakeCurrent() const {
    289     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    290         SkDebugf("Could not set the context.\n");
    291     }
    292 }
    293 
    294 std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
    295     if (eglGetCurrentContext() == fContext) {
    296         return nullptr;
    297     }
    298     return context_restorer();
    299 }
    300 
    301 void EGLGLTestContext::onPlatformSwapBuffers() const {
    302     if (!eglSwapBuffers(fDisplay, fSurface)) {
    303         SkDebugf("Could not complete eglSwapBuffers.\n");
    304     }
    305 }
    306 
    307 GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
    308     return eglGetProcAddress(procName);
    309 }
    310 
    311 static bool supports_egl_extension(EGLDisplay display, const char* extension) {
    312     size_t extensionLength = strlen(extension);
    313     const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
    314     while (const char* match = strstr(extensionsStr, extension)) {
    315         // Ensure the string we found is its own extension, not a substring of a larger extension
    316         // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
    317         if ((match == extensionsStr || match[-1] == ' ') &&
    318             (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
    319             return true;
    320         }
    321         extensionsStr = match + extensionLength;
    322     }
    323     return false;
    324 }
    325 
    326 std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
    327     if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
    328         return nullptr;
    329     }
    330     return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
    331 }
    332 
    333 EGLFenceSync::EGLFenceSync(EGLDisplay display)
    334     : fDisplay(display) {
    335     fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
    336     fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
    337     fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
    338     SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
    339 }
    340 
    341 sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
    342     EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
    343     return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
    344 }
    345 
    346 bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
    347     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
    348     return EGL_CONDITION_SATISFIED_KHR ==
    349             fEGLClientWaitSyncKHR(fDisplay,
    350                                   eglsync,
    351                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
    352                                   EGL_FOREVER_KHR);
    353 }
    354 
    355 void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
    356     EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
    357     fEGLDestroySyncKHR(fDisplay, eglsync);
    358 }
    359 
    360 GR_STATIC_ASSERT(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
    361 
    362 }  // anonymous namespace
    363 
    364 namespace sk_gpu_test {
    365 GLTestContext *CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
    366                                            GLTestContext *shareContext) {
    367     EGLGLTestContext* eglShareContext = reinterpret_cast<EGLGLTestContext*>(shareContext);
    368     EGLGLTestContext *ctx = new EGLGLTestContext(forcedGpuAPI, eglShareContext);
    369     if (!ctx->isValid()) {
    370         delete ctx;
    371         return nullptr;
    372     }
    373     return ctx;
    374 }
    375 }  // namespace sk_gpu_test
    376