Home | History | Annotate | Download | only in angle
      1 
      2 /*
      3  * Copyright 2012 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 "GLTestContext_angle.h"
     10 
     11 #include <EGL/egl.h>
     12 #include <EGL/eglext.h>
     13 
     14 #include "gl/GrGLDefines.h"
     15 #include "gl/GrGLUtil.h"
     16 
     17 #include "gl/GrGLInterface.h"
     18 #include "gl/GrGLAssembleInterface.h"
     19 #include "../ports/SkOSLibrary.h"
     20 
     21 #include <EGL/egl.h>
     22 
     23 #define EGL_PLATFORM_ANGLE_ANGLE                0x3202
     24 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE           0x3203
     25 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE      0x3207
     26 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE     0x3208
     27 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE    0x320D
     28 
     29 using sk_gpu_test::ANGLEBackend;
     30 using sk_gpu_test::ANGLEContextVersion;
     31 
     32 namespace {
     33 struct Libs {
     34     void* fGLLib;
     35     void* fEGLLib;
     36 };
     37 
     38 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
     39     const Libs* libs = reinterpret_cast<const Libs*>(ctx);
     40     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
     41     if (proc) {
     42         return proc;
     43     }
     44     proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name);
     45     if (proc) {
     46         return proc;
     47     }
     48     return eglGetProcAddress(name);
     49 }
     50 
     51 void* get_angle_egl_display(void* nativeDisplay, ANGLEBackend type) {
     52     PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
     53     eglGetPlatformDisplayEXT =
     54         (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
     55 
     56     // We expect ANGLE to support this extension
     57     if (!eglGetPlatformDisplayEXT) {
     58         return EGL_NO_DISPLAY;
     59     }
     60 
     61     EGLint typeNum = 0;
     62     switch (type) {
     63         case ANGLEBackend::kD3D9:
     64             typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
     65             break;
     66         case ANGLEBackend::kD3D11:
     67             typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
     68             break;
     69         case ANGLEBackend::kOpenGL:
     70             typeNum = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
     71             break;
     72     }
     73     const EGLint attribs[] = { EGL_PLATFORM_ANGLE_TYPE_ANGLE, typeNum, EGL_NONE };
     74     return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
     75 }
     76 
     77 class ANGLEGLContext : public sk_gpu_test::GLTestContext {
     78 public:
     79     ANGLEGLContext(ANGLEBackend, ANGLEContextVersion, ANGLEGLContext* shareContext);
     80     ~ANGLEGLContext() override;
     81 
     82     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
     83     void destroyEGLImage(GrEGLImage) const override;
     84     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
     85     std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override;
     86 
     87 private:
     88     void destroyGLContext();
     89 
     90     void onPlatformMakeCurrent() const override;
     91     void onPlatformSwapBuffers() const override;
     92     GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
     93 
     94     void*                       fContext;
     95     void*                       fDisplay;
     96     void*                       fSurface;
     97     ANGLEBackend                fType;
     98     ANGLEContextVersion         fVersion;
     99 };
    100 
    101 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version,
    102                                ANGLEGLContext* shareContext)
    103     : fContext(EGL_NO_CONTEXT)
    104     , fDisplay(EGL_NO_DISPLAY)
    105     , fSurface(EGL_NO_SURFACE)
    106     , fType(type)
    107     , fVersion(version) {
    108 
    109     EGLint numConfigs;
    110     static const EGLint configAttribs[] = {
    111         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    112         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    113         EGL_RED_SIZE, 8,
    114         EGL_GREEN_SIZE, 8,
    115         EGL_BLUE_SIZE, 8,
    116         EGL_ALPHA_SIZE, 8,
    117         EGL_NONE
    118     };
    119 
    120     fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, type);
    121     if (EGL_NO_DISPLAY == fDisplay) {
    122         SkDebugf("Could not create EGL display!");
    123         return;
    124     }
    125 
    126     EGLint majorVersion;
    127     EGLint minorVersion;
    128     eglInitialize(fDisplay, &majorVersion, &minorVersion);
    129 
    130     EGLConfig surfaceConfig;
    131     eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs);
    132 
    133     int versionNum = ANGLEContextVersion::kES2 == version ? 2 : 3;
    134     const EGLint contextAttribs[] = {
    135         EGL_CONTEXT_CLIENT_VERSION, versionNum,
    136         EGL_NONE
    137     };
    138     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
    139     fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext, contextAttribs);
    140 
    141 
    142     static const EGLint surfaceAttribs[] = {
    143         EGL_WIDTH, 1,
    144         EGL_HEIGHT, 1,
    145         EGL_NONE
    146     };
    147 
    148     fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
    149 
    150     eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
    151 
    152     sk_sp<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface());
    153     if (nullptr == gl.get()) {
    154         SkDebugf("Could not create ANGLE GL interface!\n");
    155         this->destroyGLContext();
    156         return;
    157     }
    158     if (!gl->validate()) {
    159         SkDebugf("Could not validate ANGLE GL interface!\n");
    160         this->destroyGLContext();
    161         return;
    162     }
    163 
    164     this->init(gl.release());
    165 }
    166 
    167 ANGLEGLContext::~ANGLEGLContext() {
    168     this->teardown();
    169     this->destroyGLContext();
    170 }
    171 
    172 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
    173     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
    174         return GR_EGL_NO_IMAGE;
    175     }
    176     GrEGLImage img;
    177     GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
    178                            GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
    179                            GR_EGL_NONE };
    180     // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
    181     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
    182     GR_GL_CALL_RET(this->gl(), img,
    183                    EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
    184                                   attribs));
    185     return img;
    186 }
    187 
    188 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
    189     GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
    190 }
    191 
    192 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
    193     GrGLClearErr(this->gl());
    194     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
    195         return 0;
    196     }
    197     typedef GrGLvoid (EGLAPIENTRY *EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
    198     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
    199         (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
    200     if (!glEGLImageTargetTexture2D) {
    201         return 0;
    202     }
    203     GrGLuint texID;
    204     GR_GL_CALL(this->gl(), GenTextures(1, &texID));
    205     if (!texID) {
    206         return 0;
    207     }
    208     GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
    209     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    210         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    211         return 0;
    212     }
    213     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
    214     if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
    215         GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
    216         return 0;
    217     }
    218     return texID;
    219 }
    220 
    221 std::unique_ptr<sk_gpu_test::GLTestContext> ANGLEGLContext::makeNew() const {
    222     std::unique_ptr<sk_gpu_test::GLTestContext> ctx =
    223         sk_gpu_test::MakeANGLETestContext(fType, fVersion);
    224     if (ctx) {
    225         ctx->makeCurrent();
    226     }
    227     return ctx;
    228 }
    229 
    230 void ANGLEGLContext::destroyGLContext() {
    231     if (fDisplay) {
    232         eglMakeCurrent(fDisplay, 0, 0, 0);
    233 
    234         if (fContext) {
    235             eglDestroyContext(fDisplay, fContext);
    236             fContext = EGL_NO_CONTEXT;
    237         }
    238 
    239         if (fSurface) {
    240             eglDestroySurface(fDisplay, fSurface);
    241             fSurface = EGL_NO_SURFACE;
    242         }
    243 
    244         //TODO should we close the display?
    245         fDisplay = EGL_NO_DISPLAY;
    246     }
    247 }
    248 
    249 void ANGLEGLContext::onPlatformMakeCurrent() const {
    250     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    251         SkDebugf("Could not set the context.\n");
    252     }
    253 }
    254 
    255 void ANGLEGLContext::onPlatformSwapBuffers() const {
    256     if (!eglSwapBuffers(fDisplay, fSurface)) {
    257         SkDebugf("Could not complete eglSwapBuffers.\n");
    258     }
    259 }
    260 
    261 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
    262     return eglGetProcAddress(name);
    263 }
    264 }  // anonymous namespace
    265 
    266 namespace sk_gpu_test {
    267 const GrGLInterface* CreateANGLEGLInterface() {
    268     static Libs gLibs = { nullptr, nullptr };
    269 
    270     if (nullptr == gLibs.fGLLib) {
    271         // We load the ANGLE library and never let it go
    272 #if defined _WIN32
    273         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll");
    274         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll");
    275 #elif defined SK_BUILD_FOR_MAC
    276         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib");
    277         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib");
    278 #else
    279         gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so");
    280         gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so");
    281 #endif
    282     }
    283 
    284     if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
    285         // We can't setup the interface correctly w/o the so
    286         return nullptr;
    287     }
    288 
    289     return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
    290 }
    291 
    292 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
    293                                                     GLTestContext* shareContext){
    294     ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext);
    295     std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version, angleShareContext));
    296     if (!ctx->isValid()) {
    297         return nullptr;
    298     }
    299     return ctx;
    300 }
    301 }  // namespace sk_gpu_test
    302