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