michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "GLLibraryEGL.h" michael@0: michael@0: #include "gfxCrashReporterUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "nsPrintfCString.h" michael@0: #ifdef XP_WIN michael@0: #include "nsWindowsHelpers.h" michael@0: #endif michael@0: #include "prenv.h" michael@0: #include "GLContext.h" michael@0: #include "gfxPrefs.h" michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: GLLibraryEGL sEGLLibrary; michael@0: michael@0: // should match the order of EGLExtensions, and be null-terminated. michael@0: static const char *sEGLExtensionNames[] = { michael@0: "EGL_KHR_image_base", michael@0: "EGL_KHR_image_pixmap", michael@0: "EGL_KHR_gl_texture_2D_image", michael@0: "EGL_KHR_lock_surface", michael@0: "EGL_ANGLE_surface_d3d_texture_2d_share_handle", michael@0: "EGL_EXT_create_context_robustness", michael@0: "EGL_KHR_image", michael@0: "EGL_KHR_fence_sync", michael@0: nullptr michael@0: }; michael@0: michael@0: #if defined(ANDROID) michael@0: michael@0: static PRLibrary* LoadApitraceLibrary() michael@0: { michael@0: if (!gfxPrefs::UseApitrace()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: static PRLibrary* sApitraceLibrary = nullptr; michael@0: michael@0: if (sApitraceLibrary) michael@0: return sApitraceLibrary; michael@0: michael@0: nsCString logFile = Preferences::GetCString("gfx.apitrace.logfile"); michael@0: michael@0: if (logFile.IsEmpty()) { michael@0: logFile = "firefox.trace"; michael@0: } michael@0: michael@0: // The firefox process can't write to /data/local, but it can write michael@0: // to $GRE_HOME/ michael@0: nsAutoCString logPath; michael@0: logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get()); michael@0: michael@0: // apitrace uses the TRACE_FILE environment variable to determine where michael@0: // to log trace output to michael@0: printf_stderr("Logging GL tracing output to %s", logPath.get()); michael@0: setenv("TRACE_FILE", logPath.get(), false); michael@0: michael@0: printf_stderr("Attempting load of %s\n", APITRACE_LIB); michael@0: michael@0: sApitraceLibrary = PR_LoadLibrary(APITRACE_LIB); michael@0: michael@0: return sApitraceLibrary; michael@0: } michael@0: michael@0: #endif // ANDROID michael@0: michael@0: #ifdef XP_WIN michael@0: // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here. michael@0: static PRLibrary* michael@0: LoadLibraryForEGLOnWindows(const nsAString& filename) michael@0: { michael@0: nsCOMPtr file; michael@0: nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: file->Append(filename); michael@0: PRLibrary* lib = nullptr; michael@0: rv = file->Load(&lib); michael@0: if (NS_FAILED(rv)) { michael@0: nsPrintfCString msg("Failed to load %s - Expect EGL initialization to fail", michael@0: NS_LossyConvertUTF16toASCII(filename).get()); michael@0: NS_WARNING(msg.get()); michael@0: } michael@0: return lib; michael@0: } michael@0: #endif // XP_WIN michael@0: michael@0: bool michael@0: GLLibraryEGL::EnsureInitialized() michael@0: { michael@0: if (mInitialized) { michael@0: return true; michael@0: } michael@0: michael@0: mozilla::ScopedGfxFeatureReporter reporter("EGL"); michael@0: michael@0: #ifdef XP_WIN michael@0: #ifdef MOZ_WEBGL michael@0: if (!mEGLLibrary) { michael@0: // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and michael@0: // we should look for them there. We have to load the libs in this michael@0: // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK michael@0: // libraries. This matters especially for WebRT apps which are in a different directory. michael@0: // See bug 760323 and bug 749459 michael@0: michael@0: #ifndef MOZ_D3DCOMPILER_DLL michael@0: #error MOZ_D3DCOMPILER_DLL should have been defined by the Makefile michael@0: #endif michael@0: // Windows 8.1 has d3dcompiler_47.dll in the system directory. michael@0: // Try it first. Note that _46 will never be in the system michael@0: // directory and we ship with at least _43. So there is no point michael@0: // trying _46 and _43 in the system directory. michael@0: if (!LoadLibrarySystem32(L"d3dcompiler_47.dll")) { michael@0: // Fall back to the version that we shipped with. michael@0: LoadLibraryForEGLOnWindows(NS_LITERAL_STRING(NS_STRINGIFY(MOZ_D3DCOMPILER_DLL))); michael@0: } michael@0: // intentionally leak the D3DCOMPILER_DLL library michael@0: michael@0: LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libGLESv2.dll")); michael@0: // intentionally leak the libGLESv2.dll library michael@0: michael@0: mEGLLibrary = LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libEGL.dll")); michael@0: michael@0: if (!mEGLLibrary) michael@0: return false; michael@0: } michael@0: #endif // MOZ_WEBGL michael@0: #else // !Windows michael@0: michael@0: // On non-Windows (Android) we use system copies of libEGL. We look for michael@0: // the APITrace lib, libEGL.so, and libEGL.so.1 in that order. michael@0: michael@0: #if defined(ANDROID) michael@0: if (!mEGLLibrary) michael@0: mEGLLibrary = LoadApitraceLibrary(); michael@0: #endif michael@0: michael@0: if (!mEGLLibrary) { michael@0: printf_stderr("Attempting load of libEGL.so\n"); michael@0: mEGLLibrary = PR_LoadLibrary("libEGL.so"); michael@0: } michael@0: #if defined(XP_UNIX) michael@0: if (!mEGLLibrary) { michael@0: mEGLLibrary = PR_LoadLibrary("libEGL.so.1"); michael@0: } michael@0: #endif michael@0: michael@0: if (!mEGLLibrary) { michael@0: NS_WARNING("Couldn't load EGL LIB."); michael@0: return false; michael@0: } michael@0: michael@0: #endif // !Windows michael@0: michael@0: #define SYMBOL(name) \ michael@0: { (PRFuncPtr*) &mSymbols.f##name, { "egl" #name, nullptr } } michael@0: michael@0: GLLibraryLoader::SymLoadStruct earlySymbols[] = { michael@0: SYMBOL(GetDisplay), michael@0: SYMBOL(GetCurrentSurface), michael@0: SYMBOL(GetCurrentContext), michael@0: SYMBOL(MakeCurrent), michael@0: SYMBOL(DestroyContext), michael@0: SYMBOL(CreateContext), michael@0: SYMBOL(DestroySurface), michael@0: SYMBOL(CreateWindowSurface), michael@0: SYMBOL(CreatePbufferSurface), michael@0: SYMBOL(CreatePixmapSurface), michael@0: SYMBOL(BindAPI), michael@0: SYMBOL(Initialize), michael@0: SYMBOL(ChooseConfig), michael@0: SYMBOL(GetError), michael@0: SYMBOL(GetConfigs), michael@0: SYMBOL(GetConfigAttrib), michael@0: SYMBOL(WaitNative), michael@0: SYMBOL(GetProcAddress), michael@0: SYMBOL(SwapBuffers), michael@0: SYMBOL(CopyBuffers), michael@0: SYMBOL(QueryString), michael@0: SYMBOL(QueryContext), michael@0: SYMBOL(BindTexImage), michael@0: SYMBOL(ReleaseTexImage), michael@0: SYMBOL(QuerySurface), michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) { michael@0: NS_WARNING("Couldn't find required entry points in EGL library (early init)"); michael@0: return false; michael@0: } michael@0: michael@0: mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY); michael@0: if (!fInitialize(mEGLDisplay, nullptr, nullptr)) michael@0: return false; michael@0: michael@0: const char *vendor = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR); michael@0: if (vendor && (strstr(vendor, "TransGaming") != 0 || strstr(vendor, "Google Inc.") != 0)) { michael@0: mIsANGLE = true; michael@0: } michael@0: michael@0: InitExtensions(); michael@0: michael@0: GLLibraryLoader::PlatformLookupFunction lookupFunction = michael@0: (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress; michael@0: michael@0: if (IsExtensionSupported(KHR_lock_surface)) { michael@0: GLLibraryLoader::SymLoadStruct lockSymbols[] = { michael@0: { (PRFuncPtr*) &mSymbols.fLockSurface, { "eglLockSurfaceKHR", nullptr } }, michael@0: { (PRFuncPtr*) &mSymbols.fUnlockSurface, { "eglUnlockSurfaceKHR", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, michael@0: &lockSymbols[0], michael@0: lookupFunction); michael@0: if (!success) { michael@0: NS_ERROR("EGL supports KHR_lock_surface without exposing its functions!"); michael@0: michael@0: MarkExtensionUnsupported(KHR_lock_surface); michael@0: michael@0: mSymbols.fLockSurface = nullptr; michael@0: mSymbols.fUnlockSurface = nullptr; michael@0: } michael@0: } michael@0: michael@0: if (IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle)) { michael@0: GLLibraryLoader::SymLoadStruct d3dSymbols[] = { michael@0: { (PRFuncPtr*) &mSymbols.fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, michael@0: &d3dSymbols[0], michael@0: lookupFunction); michael@0: if (!success) { michael@0: NS_ERROR("EGL supports ANGLE_surface_d3d_texture_2d_share_handle without exposing its functions!"); michael@0: michael@0: MarkExtensionUnsupported(ANGLE_surface_d3d_texture_2d_share_handle); michael@0: michael@0: mSymbols.fQuerySurfacePointerANGLE = nullptr; michael@0: } michael@0: } michael@0: michael@0: if (IsExtensionSupported(KHR_fence_sync)) { michael@0: GLLibraryLoader::SymLoadStruct syncSymbols[] = { michael@0: { (PRFuncPtr*) &mSymbols.fCreateSync, { "eglCreateSyncKHR", nullptr } }, michael@0: { (PRFuncPtr*) &mSymbols.fDestroySync, { "eglDestroySyncKHR", nullptr } }, michael@0: { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "eglClientWaitSyncKHR", nullptr } }, michael@0: { (PRFuncPtr*) &mSymbols.fGetSyncAttrib, { "eglGetSyncAttribKHR", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, michael@0: &syncSymbols[0], michael@0: lookupFunction); michael@0: if (!success) { michael@0: NS_ERROR("EGL supports KHR_fence_sync without exposing its functions!"); michael@0: michael@0: MarkExtensionUnsupported(KHR_fence_sync); michael@0: michael@0: mSymbols.fCreateSync = nullptr; michael@0: mSymbols.fDestroySync = nullptr; michael@0: mSymbols.fClientWaitSync = nullptr; michael@0: mSymbols.fGetSyncAttrib = nullptr; michael@0: } michael@0: } michael@0: michael@0: if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) { michael@0: GLLibraryLoader::SymLoadStruct imageSymbols[] = { michael@0: { (PRFuncPtr*) &mSymbols.fCreateImage, { "eglCreateImageKHR", nullptr } }, michael@0: { (PRFuncPtr*) &mSymbols.fDestroyImage, { "eglDestroyImageKHR", nullptr } }, michael@0: { nullptr, { nullptr } } michael@0: }; michael@0: michael@0: bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, michael@0: &imageSymbols[0], michael@0: lookupFunction); michael@0: if (!success) { michael@0: NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!"); michael@0: michael@0: MarkExtensionUnsupported(KHR_image); michael@0: MarkExtensionUnsupported(KHR_image_base); michael@0: MarkExtensionUnsupported(KHR_image_pixmap); michael@0: michael@0: mSymbols.fCreateImage = nullptr; michael@0: mSymbols.fDestroyImage = nullptr; michael@0: } michael@0: } else { michael@0: MarkExtensionUnsupported(KHR_image_pixmap); michael@0: } michael@0: michael@0: mInitialized = true; michael@0: reporter.SetSuccessful(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: GLLibraryEGL::InitExtensions() michael@0: { michael@0: const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS); michael@0: michael@0: if (!extensions) { michael@0: NS_WARNING("Failed to load EGL extension list!"); michael@0: return; michael@0: } michael@0: michael@0: bool debugMode = false; michael@0: #ifdef DEBUG michael@0: if (PR_GetEnv("MOZ_GL_DEBUG")) michael@0: debugMode = true; michael@0: michael@0: static bool firstRun = true; michael@0: #else michael@0: // Non-DEBUG, so never spew. michael@0: const bool firstRun = false; michael@0: #endif michael@0: michael@0: GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, sEGLExtensionNames, firstRun && debugMode); michael@0: michael@0: #ifdef DEBUG michael@0: firstRun = false; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: GLLibraryEGL::DumpEGLConfig(EGLConfig cfg) michael@0: { michael@0: int attrval; michael@0: int err; michael@0: michael@0: #define ATTR(_x) do { \ michael@0: fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval); \ michael@0: if ((err = fGetError()) != 0x3000) { \ michael@0: printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \ michael@0: } else { \ michael@0: printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \ michael@0: } \ michael@0: } while(0) michael@0: michael@0: printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg); michael@0: michael@0: ATTR(BUFFER_SIZE); michael@0: ATTR(ALPHA_SIZE); michael@0: ATTR(BLUE_SIZE); michael@0: ATTR(GREEN_SIZE); michael@0: ATTR(RED_SIZE); michael@0: ATTR(DEPTH_SIZE); michael@0: ATTR(STENCIL_SIZE); michael@0: ATTR(CONFIG_CAVEAT); michael@0: ATTR(CONFIG_ID); michael@0: ATTR(LEVEL); michael@0: ATTR(MAX_PBUFFER_HEIGHT); michael@0: ATTR(MAX_PBUFFER_PIXELS); michael@0: ATTR(MAX_PBUFFER_WIDTH); michael@0: ATTR(NATIVE_RENDERABLE); michael@0: ATTR(NATIVE_VISUAL_ID); michael@0: ATTR(NATIVE_VISUAL_TYPE); michael@0: ATTR(PRESERVED_RESOURCES); michael@0: ATTR(SAMPLES); michael@0: ATTR(SAMPLE_BUFFERS); michael@0: ATTR(SURFACE_TYPE); michael@0: ATTR(TRANSPARENT_TYPE); michael@0: ATTR(TRANSPARENT_RED_VALUE); michael@0: ATTR(TRANSPARENT_GREEN_VALUE); michael@0: ATTR(TRANSPARENT_BLUE_VALUE); michael@0: ATTR(BIND_TO_TEXTURE_RGB); michael@0: ATTR(BIND_TO_TEXTURE_RGBA); michael@0: ATTR(MIN_SWAP_INTERVAL); michael@0: ATTR(MAX_SWAP_INTERVAL); michael@0: ATTR(LUMINANCE_SIZE); michael@0: ATTR(ALPHA_MASK_SIZE); michael@0: ATTR(COLOR_BUFFER_TYPE); michael@0: ATTR(RENDERABLE_TYPE); michael@0: ATTR(CONFORMANT); michael@0: michael@0: #undef ATTR michael@0: } michael@0: michael@0: void michael@0: GLLibraryEGL::DumpEGLConfigs() michael@0: { michael@0: int nc = 0; michael@0: fGetConfigs(mEGLDisplay, nullptr, 0, &nc); michael@0: EGLConfig *ec = new EGLConfig[nc]; michael@0: fGetConfigs(mEGLDisplay, ec, nc, &nc); michael@0: michael@0: for (int i = 0; i < nc; ++i) { michael@0: printf_stderr ("========= EGL Config %d ========\n", i); michael@0: DumpEGLConfig(ec[i]); michael@0: } michael@0: michael@0: delete [] ec; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: /*static*/ void michael@0: GLLibraryEGL::BeforeGLCall(const char* glFunction) michael@0: { michael@0: if (GLContext::DebugMode()) { michael@0: if (GLContext::DebugMode() & GLContext::DebugTrace) michael@0: printf_stderr("[egl] > %s\n", glFunction); michael@0: } michael@0: } michael@0: michael@0: /*static*/ void michael@0: GLLibraryEGL::AfterGLCall(const char* glFunction) michael@0: { michael@0: if (GLContext::DebugMode() & GLContext::DebugTrace) { michael@0: printf_stderr("[egl] < %s\n", glFunction); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: } /* namespace gl */ michael@0: } /* namespace mozilla */ michael@0: