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