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