Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "GLLibraryEGL.h"
7 #include "gfxCrashReporterUtils.h"
8 #include "mozilla/Preferences.h"
9 #include "nsDirectoryServiceDefs.h"
10 #include "nsDirectoryServiceUtils.h"
11 #include "nsPrintfCString.h"
12 #ifdef XP_WIN
13 #include "nsWindowsHelpers.h"
14 #endif
15 #include "prenv.h"
16 #include "GLContext.h"
17 #include "gfxPrefs.h"
19 namespace mozilla {
20 namespace gl {
22 GLLibraryEGL sEGLLibrary;
24 // should match the order of EGLExtensions, and be null-terminated.
25 static const char *sEGLExtensionNames[] = {
26 "EGL_KHR_image_base",
27 "EGL_KHR_image_pixmap",
28 "EGL_KHR_gl_texture_2D_image",
29 "EGL_KHR_lock_surface",
30 "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
31 "EGL_EXT_create_context_robustness",
32 "EGL_KHR_image",
33 "EGL_KHR_fence_sync",
34 nullptr
35 };
37 #if defined(ANDROID)
39 static PRLibrary* LoadApitraceLibrary()
40 {
41 if (!gfxPrefs::UseApitrace()) {
42 return nullptr;
43 }
45 static PRLibrary* sApitraceLibrary = nullptr;
47 if (sApitraceLibrary)
48 return sApitraceLibrary;
50 nsCString logFile = Preferences::GetCString("gfx.apitrace.logfile");
52 if (logFile.IsEmpty()) {
53 logFile = "firefox.trace";
54 }
56 // The firefox process can't write to /data/local, but it can write
57 // to $GRE_HOME/
58 nsAutoCString logPath;
59 logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get());
61 // apitrace uses the TRACE_FILE environment variable to determine where
62 // to log trace output to
63 printf_stderr("Logging GL tracing output to %s", logPath.get());
64 setenv("TRACE_FILE", logPath.get(), false);
66 printf_stderr("Attempting load of %s\n", APITRACE_LIB);
68 sApitraceLibrary = PR_LoadLibrary(APITRACE_LIB);
70 return sApitraceLibrary;
71 }
73 #endif // ANDROID
75 #ifdef XP_WIN
76 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
77 static PRLibrary*
78 LoadLibraryForEGLOnWindows(const nsAString& filename)
79 {
80 nsCOMPtr<nsIFile> file;
81 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
82 if (NS_FAILED(rv))
83 return nullptr;
85 file->Append(filename);
86 PRLibrary* lib = nullptr;
87 rv = file->Load(&lib);
88 if (NS_FAILED(rv)) {
89 nsPrintfCString msg("Failed to load %s - Expect EGL initialization to fail",
90 NS_LossyConvertUTF16toASCII(filename).get());
91 NS_WARNING(msg.get());
92 }
93 return lib;
94 }
95 #endif // XP_WIN
97 bool
98 GLLibraryEGL::EnsureInitialized()
99 {
100 if (mInitialized) {
101 return true;
102 }
104 mozilla::ScopedGfxFeatureReporter reporter("EGL");
106 #ifdef XP_WIN
107 #ifdef MOZ_WEBGL
108 if (!mEGLLibrary) {
109 // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and
110 // we should look for them there. We have to load the libs in this
111 // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK
112 // libraries. This matters especially for WebRT apps which are in a different directory.
113 // See bug 760323 and bug 749459
115 #ifndef MOZ_D3DCOMPILER_DLL
116 #error MOZ_D3DCOMPILER_DLL should have been defined by the Makefile
117 #endif
118 // Windows 8.1 has d3dcompiler_47.dll in the system directory.
119 // Try it first. Note that _46 will never be in the system
120 // directory and we ship with at least _43. So there is no point
121 // trying _46 and _43 in the system directory.
122 if (!LoadLibrarySystem32(L"d3dcompiler_47.dll")) {
123 // Fall back to the version that we shipped with.
124 LoadLibraryForEGLOnWindows(NS_LITERAL_STRING(NS_STRINGIFY(MOZ_D3DCOMPILER_DLL)));
125 }
126 // intentionally leak the D3DCOMPILER_DLL library
128 LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libGLESv2.dll"));
129 // intentionally leak the libGLESv2.dll library
131 mEGLLibrary = LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libEGL.dll"));
133 if (!mEGLLibrary)
134 return false;
135 }
136 #endif // MOZ_WEBGL
137 #else // !Windows
139 // On non-Windows (Android) we use system copies of libEGL. We look for
140 // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
142 #if defined(ANDROID)
143 if (!mEGLLibrary)
144 mEGLLibrary = LoadApitraceLibrary();
145 #endif
147 if (!mEGLLibrary) {
148 printf_stderr("Attempting load of libEGL.so\n");
149 mEGLLibrary = PR_LoadLibrary("libEGL.so");
150 }
151 #if defined(XP_UNIX)
152 if (!mEGLLibrary) {
153 mEGLLibrary = PR_LoadLibrary("libEGL.so.1");
154 }
155 #endif
157 if (!mEGLLibrary) {
158 NS_WARNING("Couldn't load EGL LIB.");
159 return false;
160 }
162 #endif // !Windows
164 #define SYMBOL(name) \
165 { (PRFuncPtr*) &mSymbols.f##name, { "egl" #name, nullptr } }
167 GLLibraryLoader::SymLoadStruct earlySymbols[] = {
168 SYMBOL(GetDisplay),
169 SYMBOL(GetCurrentSurface),
170 SYMBOL(GetCurrentContext),
171 SYMBOL(MakeCurrent),
172 SYMBOL(DestroyContext),
173 SYMBOL(CreateContext),
174 SYMBOL(DestroySurface),
175 SYMBOL(CreateWindowSurface),
176 SYMBOL(CreatePbufferSurface),
177 SYMBOL(CreatePixmapSurface),
178 SYMBOL(BindAPI),
179 SYMBOL(Initialize),
180 SYMBOL(ChooseConfig),
181 SYMBOL(GetError),
182 SYMBOL(GetConfigs),
183 SYMBOL(GetConfigAttrib),
184 SYMBOL(WaitNative),
185 SYMBOL(GetProcAddress),
186 SYMBOL(SwapBuffers),
187 SYMBOL(CopyBuffers),
188 SYMBOL(QueryString),
189 SYMBOL(QueryContext),
190 SYMBOL(BindTexImage),
191 SYMBOL(ReleaseTexImage),
192 SYMBOL(QuerySurface),
193 { nullptr, { nullptr } }
194 };
196 if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) {
197 NS_WARNING("Couldn't find required entry points in EGL library (early init)");
198 return false;
199 }
201 mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY);
202 if (!fInitialize(mEGLDisplay, nullptr, nullptr))
203 return false;
205 const char *vendor = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
206 if (vendor && (strstr(vendor, "TransGaming") != 0 || strstr(vendor, "Google Inc.") != 0)) {
207 mIsANGLE = true;
208 }
210 InitExtensions();
212 GLLibraryLoader::PlatformLookupFunction lookupFunction =
213 (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress;
215 if (IsExtensionSupported(KHR_lock_surface)) {
216 GLLibraryLoader::SymLoadStruct lockSymbols[] = {
217 { (PRFuncPtr*) &mSymbols.fLockSurface, { "eglLockSurfaceKHR", nullptr } },
218 { (PRFuncPtr*) &mSymbols.fUnlockSurface, { "eglUnlockSurfaceKHR", nullptr } },
219 { nullptr, { nullptr } }
220 };
222 bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary,
223 &lockSymbols[0],
224 lookupFunction);
225 if (!success) {
226 NS_ERROR("EGL supports KHR_lock_surface without exposing its functions!");
228 MarkExtensionUnsupported(KHR_lock_surface);
230 mSymbols.fLockSurface = nullptr;
231 mSymbols.fUnlockSurface = nullptr;
232 }
233 }
235 if (IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle)) {
236 GLLibraryLoader::SymLoadStruct d3dSymbols[] = {
237 { (PRFuncPtr*) &mSymbols.fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", nullptr } },
238 { nullptr, { nullptr } }
239 };
241 bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary,
242 &d3dSymbols[0],
243 lookupFunction);
244 if (!success) {
245 NS_ERROR("EGL supports ANGLE_surface_d3d_texture_2d_share_handle without exposing its functions!");
247 MarkExtensionUnsupported(ANGLE_surface_d3d_texture_2d_share_handle);
249 mSymbols.fQuerySurfacePointerANGLE = nullptr;
250 }
251 }
253 if (IsExtensionSupported(KHR_fence_sync)) {
254 GLLibraryLoader::SymLoadStruct syncSymbols[] = {
255 { (PRFuncPtr*) &mSymbols.fCreateSync, { "eglCreateSyncKHR", nullptr } },
256 { (PRFuncPtr*) &mSymbols.fDestroySync, { "eglDestroySyncKHR", nullptr } },
257 { (PRFuncPtr*) &mSymbols.fClientWaitSync, { "eglClientWaitSyncKHR", nullptr } },
258 { (PRFuncPtr*) &mSymbols.fGetSyncAttrib, { "eglGetSyncAttribKHR", nullptr } },
259 { nullptr, { nullptr } }
260 };
262 bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary,
263 &syncSymbols[0],
264 lookupFunction);
265 if (!success) {
266 NS_ERROR("EGL supports KHR_fence_sync without exposing its functions!");
268 MarkExtensionUnsupported(KHR_fence_sync);
270 mSymbols.fCreateSync = nullptr;
271 mSymbols.fDestroySync = nullptr;
272 mSymbols.fClientWaitSync = nullptr;
273 mSymbols.fGetSyncAttrib = nullptr;
274 }
275 }
277 if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) {
278 GLLibraryLoader::SymLoadStruct imageSymbols[] = {
279 { (PRFuncPtr*) &mSymbols.fCreateImage, { "eglCreateImageKHR", nullptr } },
280 { (PRFuncPtr*) &mSymbols.fDestroyImage, { "eglDestroyImageKHR", nullptr } },
281 { nullptr, { nullptr } }
282 };
284 bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary,
285 &imageSymbols[0],
286 lookupFunction);
287 if (!success) {
288 NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!");
290 MarkExtensionUnsupported(KHR_image);
291 MarkExtensionUnsupported(KHR_image_base);
292 MarkExtensionUnsupported(KHR_image_pixmap);
294 mSymbols.fCreateImage = nullptr;
295 mSymbols.fDestroyImage = nullptr;
296 }
297 } else {
298 MarkExtensionUnsupported(KHR_image_pixmap);
299 }
301 mInitialized = true;
302 reporter.SetSuccessful();
303 return true;
304 }
306 void
307 GLLibraryEGL::InitExtensions()
308 {
309 const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
311 if (!extensions) {
312 NS_WARNING("Failed to load EGL extension list!");
313 return;
314 }
316 bool debugMode = false;
317 #ifdef DEBUG
318 if (PR_GetEnv("MOZ_GL_DEBUG"))
319 debugMode = true;
321 static bool firstRun = true;
322 #else
323 // Non-DEBUG, so never spew.
324 const bool firstRun = false;
325 #endif
327 GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, sEGLExtensionNames, firstRun && debugMode);
329 #ifdef DEBUG
330 firstRun = false;
331 #endif
332 }
334 void
335 GLLibraryEGL::DumpEGLConfig(EGLConfig cfg)
336 {
337 int attrval;
338 int err;
340 #define ATTR(_x) do { \
341 fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
342 if ((err = fGetError()) != 0x3000) { \
343 printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \
344 } else { \
345 printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \
346 } \
347 } while(0)
349 printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg);
351 ATTR(BUFFER_SIZE);
352 ATTR(ALPHA_SIZE);
353 ATTR(BLUE_SIZE);
354 ATTR(GREEN_SIZE);
355 ATTR(RED_SIZE);
356 ATTR(DEPTH_SIZE);
357 ATTR(STENCIL_SIZE);
358 ATTR(CONFIG_CAVEAT);
359 ATTR(CONFIG_ID);
360 ATTR(LEVEL);
361 ATTR(MAX_PBUFFER_HEIGHT);
362 ATTR(MAX_PBUFFER_PIXELS);
363 ATTR(MAX_PBUFFER_WIDTH);
364 ATTR(NATIVE_RENDERABLE);
365 ATTR(NATIVE_VISUAL_ID);
366 ATTR(NATIVE_VISUAL_TYPE);
367 ATTR(PRESERVED_RESOURCES);
368 ATTR(SAMPLES);
369 ATTR(SAMPLE_BUFFERS);
370 ATTR(SURFACE_TYPE);
371 ATTR(TRANSPARENT_TYPE);
372 ATTR(TRANSPARENT_RED_VALUE);
373 ATTR(TRANSPARENT_GREEN_VALUE);
374 ATTR(TRANSPARENT_BLUE_VALUE);
375 ATTR(BIND_TO_TEXTURE_RGB);
376 ATTR(BIND_TO_TEXTURE_RGBA);
377 ATTR(MIN_SWAP_INTERVAL);
378 ATTR(MAX_SWAP_INTERVAL);
379 ATTR(LUMINANCE_SIZE);
380 ATTR(ALPHA_MASK_SIZE);
381 ATTR(COLOR_BUFFER_TYPE);
382 ATTR(RENDERABLE_TYPE);
383 ATTR(CONFORMANT);
385 #undef ATTR
386 }
388 void
389 GLLibraryEGL::DumpEGLConfigs()
390 {
391 int nc = 0;
392 fGetConfigs(mEGLDisplay, nullptr, 0, &nc);
393 EGLConfig *ec = new EGLConfig[nc];
394 fGetConfigs(mEGLDisplay, ec, nc, &nc);
396 for (int i = 0; i < nc; ++i) {
397 printf_stderr ("========= EGL Config %d ========\n", i);
398 DumpEGLConfig(ec[i]);
399 }
401 delete [] ec;
402 }
404 #ifdef DEBUG
405 /*static*/ void
406 GLLibraryEGL::BeforeGLCall(const char* glFunction)
407 {
408 if (GLContext::DebugMode()) {
409 if (GLContext::DebugMode() & GLContext::DebugTrace)
410 printf_stderr("[egl] > %s\n", glFunction);
411 }
412 }
414 /*static*/ void
415 GLLibraryEGL::AfterGLCall(const char* glFunction)
416 {
417 if (GLContext::DebugMode() & GLContext::DebugTrace) {
418 printf_stderr("[egl] < %s\n", glFunction);
419 }
420 }
421 #endif
423 } /* namespace gl */
424 } /* namespace mozilla */