1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "GLTestContext_angle.h" 9 10 #include <EGL/egl.h> 11 #include <EGL/eglext.h> 12 13 #include "gl/GrGLDefines.h" 14 #include "gl/GrGLUtil.h" 15 16 #include "gl/GrGLInterface.h" 17 #include "gl/GrGLAssembleInterface.h" 18 #include "../ports/SkOSLibrary.h" 19 20 #include <EGL/egl.h> 21 22 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202 23 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 24 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 25 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 26 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D 27 28 using sk_gpu_test::ANGLEBackend; 29 using sk_gpu_test::ANGLEContextVersion; 30 31 namespace { 32 struct Libs { 33 void* fGLLib; 34 void* fEGLLib; 35 }; 36 37 std::function<void()> context_restorer() { 38 auto display = eglGetCurrentDisplay(); 39 auto dsurface = eglGetCurrentSurface(EGL_DRAW); 40 auto rsurface = eglGetCurrentSurface(EGL_READ); 41 auto context = eglGetCurrentContext(); 42 return [display, dsurface, rsurface, context] { 43 eglMakeCurrent(display, dsurface, rsurface, context); 44 }; 45 } 46 47 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) { 48 const Libs* libs = reinterpret_cast<const Libs*>(ctx); 49 GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name); 50 if (proc) { 51 return proc; 52 } 53 proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name); 54 if (proc) { 55 return proc; 56 } 57 return eglGetProcAddress(name); 58 } 59 60 void* get_angle_egl_display(void* nativeDisplay, ANGLEBackend type) { 61 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; 62 eglGetPlatformDisplayEXT = 63 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); 64 65 // We expect ANGLE to support this extension 66 if (!eglGetPlatformDisplayEXT) { 67 return EGL_NO_DISPLAY; 68 } 69 70 EGLint typeNum = 0; 71 switch (type) { 72 case ANGLEBackend::kD3D9: 73 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE; 74 break; 75 case ANGLEBackend::kD3D11: 76 typeNum = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; 77 break; 78 case ANGLEBackend::kOpenGL: 79 typeNum = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; 80 break; 81 } 82 const EGLint attribs[] = { EGL_PLATFORM_ANGLE_TYPE_ANGLE, typeNum, EGL_NONE }; 83 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs); 84 } 85 86 class ANGLEGLContext : public sk_gpu_test::GLTestContext { 87 public: 88 ANGLEGLContext(ANGLEBackend, ANGLEContextVersion, ANGLEGLContext* shareContext, void* display); 89 ~ANGLEGLContext() override; 90 91 GrEGLImage texture2DToEGLImage(GrGLuint texID) const override; 92 void destroyEGLImage(GrEGLImage) const override; 93 GrGLuint eglImageToExternalTexture(GrEGLImage) const override; 94 std::unique_ptr<sk_gpu_test::GLTestContext> makeNew() const override; 95 96 private: 97 void destroyGLContext(); 98 99 void onPlatformMakeCurrent() const override; 100 std::function<void()> onPlatformGetAutoContextRestore() const override; 101 void onPlatformSwapBuffers() const override; 102 GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override; 103 104 void* fContext; 105 void* fDisplay; 106 void* fSurface; 107 ANGLEBackend fType; 108 ANGLEContextVersion fVersion; 109 110 #ifdef SK_BUILD_FOR_WIN 111 HWND fWindow; 112 HDC fDeviceContext; 113 static ATOM gWC; 114 #endif 115 }; 116 117 #ifdef SK_BUILD_FOR_WIN 118 ATOM ANGLEGLContext::gWC = 0; 119 #endif 120 121 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version, 122 ANGLEGLContext* shareContext, void* display) 123 : fContext(EGL_NO_CONTEXT) 124 , fDisplay(display) 125 , fSurface(EGL_NO_SURFACE) 126 , fType(type) 127 , fVersion(version) { 128 #ifdef SK_BUILD_FOR_WIN 129 fWindow = nullptr; 130 fDeviceContext = nullptr; 131 132 if (EGL_NO_DISPLAY == fDisplay) { 133 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr); 134 135 if (!gWC) { 136 WNDCLASS wc; 137 wc.cbClsExtra = 0; 138 wc.cbWndExtra = 0; 139 wc.hbrBackground = nullptr; 140 wc.hCursor = LoadCursor(nullptr, IDC_ARROW); 141 wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); 142 wc.hInstance = hInstance; 143 wc.lpfnWndProc = (WNDPROC) DefWindowProc; 144 wc.lpszClassName = TEXT("ANGLE-win"); 145 wc.lpszMenuName = nullptr; 146 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 147 148 gWC = RegisterClass(&wc); 149 if (!gWC) { 150 SkDebugf("Could not register window class.\n"); 151 return; 152 } 153 } 154 if (!(fWindow = CreateWindow(TEXT("ANGLE-win"), 155 TEXT("The Invisible Man"), 156 WS_OVERLAPPEDWINDOW, 157 0, 0, 1, 1, 158 nullptr, nullptr, 159 hInstance, nullptr))) { 160 SkDebugf("Could not create window.\n"); 161 return; 162 } 163 164 if (!(fDeviceContext = GetDC(fWindow))) { 165 SkDebugf("Could not get device context.\n"); 166 this->destroyGLContext(); 167 return; 168 } 169 170 fDisplay = get_angle_egl_display(fDeviceContext, type); 171 } 172 #else 173 SkASSERT(EGL_NO_DISPLAY == fDisplay); 174 fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, type); 175 #endif 176 if (EGL_NO_DISPLAY == fDisplay) { 177 SkDebugf("Could not create EGL display!"); 178 return; 179 } 180 181 EGLint majorVersion; 182 EGLint minorVersion; 183 if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) { 184 SkDebugf("Could not initialize display!"); 185 this->destroyGLContext(); 186 return; 187 } 188 189 EGLint numConfigs; 190 static const EGLint configAttribs[] = { 191 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 192 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 193 EGL_RED_SIZE, 8, 194 EGL_GREEN_SIZE, 8, 195 EGL_BLUE_SIZE, 8, 196 EGL_ALPHA_SIZE, 8, 197 EGL_NONE 198 }; 199 200 EGLConfig surfaceConfig; 201 if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) { 202 SkDebugf("Could not create choose config!"); 203 this->destroyGLContext(); 204 return; 205 } 206 207 int versionNum = ANGLEContextVersion::kES2 == version ? 2 : 3; 208 const EGLint contextAttribs[] = { 209 EGL_CONTEXT_CLIENT_VERSION, versionNum, 210 EGL_NONE 211 }; 212 EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr; 213 fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext, contextAttribs); 214 if (EGL_NO_CONTEXT == fContext) { 215 SkDebugf("Could not create context!"); 216 this->destroyGLContext(); 217 return; 218 } 219 220 static const EGLint surfaceAttribs[] = { 221 EGL_WIDTH, 1, 222 EGL_HEIGHT, 1, 223 EGL_NONE 224 }; 225 226 fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs); 227 228 SkScopeExit restorer(context_restorer()); 229 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 230 SkDebugf("Could not set the context."); 231 this->destroyGLContext(); 232 return; 233 } 234 235 sk_sp<const GrGLInterface> gl = sk_gpu_test::CreateANGLEGLInterface(); 236 if (nullptr == gl.get()) { 237 SkDebugf("Could not create ANGLE GL interface!\n"); 238 this->destroyGLContext(); 239 return; 240 } 241 if (!gl->validate()) { 242 SkDebugf("Could not validate ANGLE GL interface!\n"); 243 this->destroyGLContext(); 244 return; 245 } 246 247 #ifdef SK_DEBUG 248 // Verify that the interface we requested was actually returned to us 249 const GrGLubyte* rendererUByte; 250 GR_GL_CALL_RET(gl.get(), rendererUByte, GetString(GR_GL_RENDERER)); 251 const char* renderer = reinterpret_cast<const char*>(rendererUByte); 252 switch (type) { 253 case ANGLEBackend::kD3D9: 254 SkASSERT(strstr(renderer, "Direct3D9")); 255 break; 256 case ANGLEBackend::kD3D11: 257 SkASSERT(strstr(renderer, "Direct3D11")); 258 break; 259 case ANGLEBackend::kOpenGL: 260 SkASSERT(strstr(renderer, "OpenGL")); 261 break; 262 } 263 #endif 264 265 this->init(std::move(gl)); 266 } 267 268 ANGLEGLContext::~ANGLEGLContext() { 269 this->teardown(); 270 this->destroyGLContext(); 271 } 272 273 GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const { 274 if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) { 275 return GR_EGL_NO_IMAGE; 276 } 277 GrEGLImage img; 278 GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, 279 GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE, 280 GR_EGL_NONE }; 281 // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer. 282 GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID); 283 GR_GL_CALL_RET(this->gl(), img, 284 EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, 285 attribs)); 286 return img; 287 } 288 289 void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const { 290 GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image)); 291 } 292 293 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const { 294 GrGLClearErr(this->gl()); 295 if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) { 296 return 0; 297 } 298 typedef GrGLvoid (EGLAPIENTRY *EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage); 299 EGLImageTargetTexture2DProc glEGLImageTargetTexture2D = 300 (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES"); 301 if (!glEGLImageTargetTexture2D) { 302 return 0; 303 } 304 GrGLuint texID; 305 GR_GL_CALL(this->gl(), GenTextures(1, &texID)); 306 if (!texID) { 307 return 0; 308 } 309 GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID)); 310 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) { 311 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID)); 312 return 0; 313 } 314 glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image); 315 if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) { 316 GR_GL_CALL(this->gl(), DeleteTextures(1, &texID)); 317 return 0; 318 } 319 return texID; 320 } 321 322 std::unique_ptr<sk_gpu_test::GLTestContext> ANGLEGLContext::makeNew() const { 323 // For EGLImage sharing between contexts to work in ANGLE the two contexts 324 // need to share the same display 325 std::unique_ptr<sk_gpu_test::GLTestContext> ctx = 326 sk_gpu_test::MakeANGLETestContext(fType, fVersion, nullptr, fDisplay); 327 if (ctx) { 328 ctx->makeCurrent(); 329 } 330 return ctx; 331 } 332 333 void ANGLEGLContext::destroyGLContext() { 334 if (EGL_NO_DISPLAY != fDisplay) { 335 if (eglGetCurrentContext() == fContext) { 336 // This will ensure that the context is immediately deleted. 337 eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 338 } 339 340 if (EGL_NO_CONTEXT != fContext) { 341 eglDestroyContext(fDisplay, fContext); 342 fContext = EGL_NO_CONTEXT; 343 } 344 345 if (EGL_NO_SURFACE != fSurface) { 346 eglDestroySurface(fDisplay, fSurface); 347 fSurface = EGL_NO_SURFACE; 348 } 349 350 eglTerminate(fDisplay); 351 fDisplay = EGL_NO_DISPLAY; 352 } 353 354 #ifdef SK_BUILD_FOR_WIN 355 if (fWindow) { 356 if (fDeviceContext) { 357 ReleaseDC(fWindow, fDeviceContext); 358 fDeviceContext = 0; 359 } 360 361 DestroyWindow(fWindow); 362 fWindow = 0; 363 } 364 #endif 365 } 366 367 void ANGLEGLContext::onPlatformMakeCurrent() const { 368 if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 369 SkDebugf("Could not set the context 0x%x.\n", eglGetError()); 370 } 371 } 372 373 std::function<void()> ANGLEGLContext::onPlatformGetAutoContextRestore() const { 374 if (eglGetCurrentContext() == fContext) { 375 return nullptr; 376 } 377 return context_restorer(); 378 } 379 380 void ANGLEGLContext::onPlatformSwapBuffers() const { 381 if (!eglSwapBuffers(fDisplay, fSurface)) { 382 SkDebugf("Could not complete eglSwapBuffers.\n"); 383 } 384 } 385 386 GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const { 387 return eglGetProcAddress(name); 388 } 389 } // anonymous namespace 390 391 namespace sk_gpu_test { 392 sk_sp<const GrGLInterface> CreateANGLEGLInterface() { 393 static Libs gLibs = { nullptr, nullptr }; 394 395 if (nullptr == gLibs.fGLLib) { 396 // We load the ANGLE library and never let it go 397 #if defined _WIN32 398 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll"); 399 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll"); 400 #elif defined SK_BUILD_FOR_MAC 401 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib"); 402 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib"); 403 #else 404 gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so"); 405 gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so"); 406 #endif 407 } 408 409 if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) { 410 // We can't setup the interface correctly w/o the so 411 return nullptr; 412 } 413 414 return GrGLMakeAssembledGLESInterface(&gLibs, angle_get_gl_proc); 415 } 416 417 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version, 418 GLTestContext* shareContext, void* display){ 419 ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext); 420 std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version, 421 angleShareContext, display)); 422 if (!ctx->isValid()) { 423 return nullptr; 424 } 425 return ctx; 426 } 427 } // namespace sk_gpu_test 428