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