Line data Source code
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/. */
4 :
5 : #include "GLLibraryEGL.h"
6 :
7 : #include "angle/Platform.h"
8 : #include "gfxConfig.h"
9 : #include "gfxCrashReporterUtils.h"
10 : #include "gfxUtils.h"
11 : #include "mozilla/Preferences.h"
12 : #include "mozilla/Assertions.h"
13 : #include "mozilla/Telemetry.h"
14 : #include "mozilla/Tokenizer.h"
15 : #include "mozilla/ScopeExit.h"
16 : #include "mozilla/Unused.h"
17 : #include "mozilla/webrender/RenderThread.h"
18 : #include "nsDirectoryServiceDefs.h"
19 : #include "nsDirectoryServiceUtils.h"
20 : #include "nsIGfxInfo.h"
21 : #include "nsPrintfCString.h"
22 : #ifdef XP_WIN
23 : #include "nsWindowsHelpers.h"
24 : #endif
25 : #include "OGLShaderProgram.h"
26 : #include "prenv.h"
27 : #include "prsystem.h"
28 : #include "GLContext.h"
29 : #include "GLContextProvider.h"
30 : #include "gfxPrefs.h"
31 : #include "ScopedGLHelpers.h"
32 :
33 : namespace mozilla {
34 : namespace gl {
35 :
36 3 : StaticMutex GLLibraryEGL::sMutex;
37 3 : GLLibraryEGL sEGLLibrary;
38 : #ifdef MOZ_B2G
39 : MOZ_THREAD_LOCAL(EGLContext) GLLibraryEGL::sCurrentContext;
40 : #endif
41 :
42 : // should match the order of EGLExtensions, and be null-terminated.
43 : static const char* sEGLExtensionNames[] = {
44 : "EGL_KHR_image_base",
45 : "EGL_KHR_image_pixmap",
46 : "EGL_KHR_gl_texture_2D_image",
47 : "EGL_KHR_lock_surface",
48 : "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
49 : "EGL_EXT_create_context_robustness",
50 : "EGL_KHR_image",
51 : "EGL_KHR_fence_sync",
52 : "EGL_ANDROID_native_fence_sync",
53 : "EGL_ANDROID_image_crop",
54 : "EGL_ANGLE_platform_angle",
55 : "EGL_ANGLE_platform_angle_d3d",
56 : "EGL_ANGLE_d3d_share_handle_client_buffer",
57 : "EGL_KHR_create_context",
58 : "EGL_KHR_stream",
59 : "EGL_KHR_stream_consumer_gltexture",
60 : "EGL_EXT_device_base",
61 : "EGL_EXT_device_query",
62 : "EGL_NV_stream_consumer_gltexture_yuv",
63 : "EGL_ANGLE_stream_producer_d3d_texture_nv12",
64 : };
65 :
66 : #if defined(ANDROID)
67 :
68 : static PRLibrary* LoadApitraceLibrary()
69 : {
70 : // Initialization of gfx prefs here is only needed during the unit tests...
71 : gfxPrefs::GetSingleton();
72 : if (!gfxPrefs::UseApitrace()) {
73 : return nullptr;
74 : }
75 :
76 : static PRLibrary* sApitraceLibrary = nullptr;
77 :
78 : if (sApitraceLibrary)
79 : return sApitraceLibrary;
80 :
81 : nsCString logFile = Preferences::GetCString("gfx.apitrace.logfile");
82 :
83 : if (logFile.IsEmpty()) {
84 : logFile = "firefox.trace";
85 : }
86 :
87 : // The firefox process can't write to /data/local, but it can write
88 : // to $GRE_HOME/
89 : nsAutoCString logPath;
90 : logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get());
91 :
92 : // apitrace uses the TRACE_FILE environment variable to determine where
93 : // to log trace output to
94 : printf_stderr("Logging GL tracing output to %s", logPath.get());
95 : setenv("TRACE_FILE", logPath.get(), false);
96 :
97 : printf_stderr("Attempting load of %s\n", APITRACE_LIB);
98 :
99 : sApitraceLibrary = PR_LoadLibrary(APITRACE_LIB);
100 :
101 : return sApitraceLibrary;
102 : }
103 :
104 : #endif // ANDROID
105 :
106 : #ifdef XP_WIN
107 : // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
108 : static PRLibrary*
109 : LoadLibraryForEGLOnWindows(const nsAString& filename)
110 : {
111 : nsAutoCString path(gfx::gfxVars::GREDirectory());
112 : path.Append(PR_GetDirectorySeparator());
113 : path.Append(ToNewUTF8String(filename));
114 :
115 : PRLibSpec lspec;
116 : lspec.type = PR_LibSpec_Pathname;
117 : lspec.value.pathname = path.get();
118 : return PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
119 : }
120 :
121 : #endif // XP_WIN
122 :
123 : static EGLDisplay
124 0 : GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType)
125 : {
126 : EGLint attrib_list[] = { LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
127 : LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
128 : // Requires:
129 : LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
130 : LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
131 0 : LOCAL_EGL_NONE };
132 : EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_ANGLE_ANGLE,
133 : displayType,
134 0 : attrib_list);
135 :
136 0 : if (display == EGL_NO_DISPLAY) {
137 0 : const EGLint err = egl.fGetError();
138 0 : if (err != LOCAL_EGL_SUCCESS) {
139 0 : gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
140 0 : MOZ_CRASH("GFX: Unexpected GL error.");
141 : }
142 0 : return EGL_NO_DISPLAY;
143 : }
144 :
145 0 : if (!egl.fInitialize(display, nullptr, nullptr))
146 0 : return EGL_NO_DISPLAY;
147 :
148 0 : return display;
149 : }
150 :
151 : static bool
152 0 : IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
153 : nsACString* const out_failureId)
154 : {
155 0 : if (wr::RenderThread::IsInRenderThread()) {
156 : // We can only enter here with WebRender, so assert that this is a
157 : // WebRender-enabled build.
158 : #ifndef MOZ_BUILD_WEBRENDER
159 : MOZ_ASSERT(false);
160 : #endif
161 0 : return true;
162 : }
163 : int32_t angleSupport;
164 0 : nsCString failureId;
165 : gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
166 : nsIGfxInfo::FEATURE_WEBGL_ANGLE,
167 : failureId,
168 0 : &angleSupport);
169 0 : if (failureId.IsEmpty() && angleSupport != nsIGfxInfo::FEATURE_STATUS_OK) {
170 : // This shouldn't happen, if we see this it's because we've missed
171 : // some failure paths
172 0 : failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_NOT_OK");
173 : }
174 0 : if (out_failureId->IsEmpty()) {
175 0 : *out_failureId = failureId;
176 : }
177 0 : return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK);
178 : }
179 :
180 : static EGLDisplay
181 0 : GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
182 : {
183 0 : EGLDisplay display = egl.fGetDisplay(displayType);
184 0 : if (display == EGL_NO_DISPLAY)
185 0 : return EGL_NO_DISPLAY;
186 :
187 0 : if (!egl.fInitialize(display, nullptr, nullptr))
188 0 : return EGL_NO_DISPLAY;
189 :
190 0 : return display;
191 : }
192 :
193 0 : class AngleErrorReporting: public angle::Platform {
194 : public:
195 3 : AngleErrorReporting()
196 3 : {
197 : // No static constructor
198 3 : }
199 :
200 0 : void SetFailureId(nsACString* const aFailureId)
201 : {
202 0 : mFailureId = aFailureId;
203 0 : }
204 :
205 0 : void logError(const char *errorMessage) override
206 : {
207 0 : if (!mFailureId) {
208 0 : return;
209 : }
210 :
211 0 : nsCString str(errorMessage);
212 0 : Tokenizer tokenizer(str);
213 :
214 : // Parse "ANGLE Display::initialize error " << error.getID() << ": "
215 : // << error.getMessage()
216 0 : nsCString currWord;
217 0 : Tokenizer::Token intToken;
218 0 : if (tokenizer.CheckWord("ANGLE") &&
219 0 : tokenizer.CheckWhite() &&
220 0 : tokenizer.CheckWord("Display") &&
221 0 : tokenizer.CheckChar(':') &&
222 0 : tokenizer.CheckChar(':') &&
223 0 : tokenizer.CheckWord("initialize") &&
224 0 : tokenizer.CheckWhite() &&
225 0 : tokenizer.CheckWord("error") &&
226 0 : tokenizer.CheckWhite() &&
227 0 : tokenizer.Check(Tokenizer::TOKEN_INTEGER, intToken)) {
228 0 : *mFailureId = "FAILURE_ID_ANGLE_ID_";
229 0 : mFailureId->AppendPrintf("%" PRIu64, intToken.AsInteger());
230 : } else {
231 0 : *mFailureId = "FAILURE_ID_ANGLE_UNKNOWN";
232 : }
233 : }
234 : private:
235 : nsACString* mFailureId;
236 : };
237 :
238 3 : AngleErrorReporting gAngleErrorReporter;
239 :
240 : static EGLDisplay
241 0 : GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl, nsACString* const out_failureId)
242 : {
243 0 : EGLDisplay ret = 0;
244 :
245 0 : if (wr::RenderThread::IsInRenderThread()) {
246 0 : return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
247 : }
248 :
249 0 : FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
250 :
251 0 : if (!gfxPrefs::WebGLANGLETryD3D11())
252 0 : d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
253 0 : NS_LITERAL_CSTRING("FAILURE_ID_ANGLE_PREF"));
254 :
255 0 : if (gfxPrefs::WebGLANGLEForceD3D11())
256 0 : d3d11ANGLE.UserForceEnable("User force-enabled D3D11 ANGLE on disabled hardware");
257 :
258 0 : gAngleErrorReporter.SetFailureId(out_failureId);
259 0 : egl.fANGLEPlatformInitialize(&gAngleErrorReporter);
260 :
261 0 : auto guardShutdown = mozilla::MakeScopeExit([&] {
262 0 : gAngleErrorReporter.SetFailureId(nullptr);
263 : // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
264 : // ANGLE display is destroyed. However gAngleErrorReporter
265 : // will live longer than the ANGLE display so we're fine.
266 0 : });
267 :
268 0 : if (gfxConfig::IsForcedOnByUser(Feature::D3D11_HW_ANGLE)) {
269 0 : return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
270 : }
271 :
272 0 : if (d3d11ANGLE.IsEnabled()) {
273 0 : ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
274 : }
275 :
276 0 : if (!ret) {
277 0 : ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY);
278 : }
279 :
280 0 : if (!ret && out_failureId->IsEmpty()) {
281 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_NO_DISP");
282 : }
283 :
284 0 : return ret;
285 : }
286 :
287 : bool
288 0 : GLLibraryEGL::ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface)
289 : {
290 0 : StaticMutexAutoUnlock lock(sMutex);
291 0 : if (!mReadbackGL) {
292 0 : nsCString discardFailureId;
293 0 : mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE,
294 0 : &discardFailureId);
295 : }
296 :
297 0 : ScopedTexture destTex(mReadbackGL);
298 0 : const GLuint target = mReadbackGL->GetPreferredEGLImageTextureTarget();
299 0 : ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target);
300 0 : mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
301 0 : mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
302 0 : mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
303 0 : mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
304 0 : mReadbackGL->fEGLImageTargetTexture2D(target, image);
305 :
306 : ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target,
307 0 : out_surface->GetFormat());
308 0 : int shaderConfig = config.mFeatures;
309 0 : mReadbackGL->ReadTexImageHelper()->ReadTexImage(out_surface, 0, target,
310 0 : out_surface->GetSize(), shaderConfig);
311 :
312 0 : return true;
313 : }
314 :
315 : bool
316 0 : GLLibraryEGL::EnsureInitialized(bool forceAccel, nsACString* const out_failureId)
317 : {
318 0 : if (mInitialized) {
319 0 : return true;
320 : }
321 :
322 0 : mozilla::ScopedGfxFeatureReporter reporter("EGL");
323 :
324 : #ifdef MOZ_B2G
325 : if (!sCurrentContext.init())
326 : MOZ_CRASH("GFX: Tls init failed");
327 : #endif
328 :
329 : #ifdef XP_WIN
330 : if (!mEGLLibrary) {
331 : // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and
332 : // we should look for them there. We have to load the libs in this
333 : // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK
334 : // libraries. This matters especially for WebRT apps which are in a different directory.
335 : // See bug 760323 and bug 749459
336 :
337 : // Also note that we intentionally leak the libs we load.
338 :
339 : do {
340 : // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
341 : // Try it first. Note that _46 will never be in the system
342 : // directory. So there is no point trying _46 in the system
343 : // directory.
344 :
345 : if (LoadLibrarySystem32(L"d3dcompiler_47.dll"))
346 : break;
347 :
348 : #ifdef MOZ_D3DCOMPILER_VISTA_DLL
349 : if (LoadLibraryForEGLOnWindows(NS_LITERAL_STRING(NS_STRINGIFY(MOZ_D3DCOMPILER_VISTA_DLL))))
350 : break;
351 : #endif
352 :
353 : MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
354 : } while (false);
355 :
356 : LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libGLESv2.dll"));
357 :
358 : mEGLLibrary = LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libEGL.dll"));
359 :
360 : if (!mEGLLibrary) {
361 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_LOAD");
362 : return false;
363 : }
364 : }
365 :
366 : #else // !Windows
367 :
368 : // On non-Windows (Android) we use system copies of libEGL. We look for
369 : // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
370 :
371 : #if defined(ANDROID)
372 : if (!mEGLLibrary)
373 : mEGLLibrary = LoadApitraceLibrary();
374 : #endif
375 :
376 0 : if (!mEGLLibrary) {
377 0 : printf_stderr("Attempting load of libEGL.so\n");
378 0 : mEGLLibrary = PR_LoadLibrary("libEGL.so");
379 : }
380 : #if defined(XP_UNIX)
381 0 : if (!mEGLLibrary) {
382 0 : mEGLLibrary = PR_LoadLibrary("libEGL.so.1");
383 : }
384 : #endif
385 :
386 0 : if (!mEGLLibrary) {
387 0 : NS_WARNING("Couldn't load EGL LIB.");
388 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_LOAD_2");
389 0 : return false;
390 : }
391 :
392 : #endif // !Windows
393 :
394 : #define SYMBOL(X) { (PRFuncPtr*)&mSymbols.f##X, { "egl" #X, nullptr } }
395 : #define END_OF_SYMBOLS { nullptr, { nullptr } }
396 :
397 : GLLibraryLoader::SymLoadStruct earlySymbols[] = {
398 0 : SYMBOL(GetDisplay),
399 0 : SYMBOL(Terminate),
400 0 : SYMBOL(GetCurrentSurface),
401 0 : SYMBOL(GetCurrentContext),
402 0 : SYMBOL(MakeCurrent),
403 0 : SYMBOL(DestroyContext),
404 0 : SYMBOL(CreateContext),
405 0 : SYMBOL(DestroySurface),
406 0 : SYMBOL(CreateWindowSurface),
407 0 : SYMBOL(CreatePbufferSurface),
408 0 : SYMBOL(CreatePbufferFromClientBuffer),
409 0 : SYMBOL(CreatePixmapSurface),
410 0 : SYMBOL(BindAPI),
411 0 : SYMBOL(Initialize),
412 0 : SYMBOL(ChooseConfig),
413 0 : SYMBOL(GetError),
414 0 : SYMBOL(GetConfigs),
415 0 : SYMBOL(GetConfigAttrib),
416 0 : SYMBOL(WaitNative),
417 0 : SYMBOL(GetProcAddress),
418 0 : SYMBOL(SwapBuffers),
419 0 : SYMBOL(CopyBuffers),
420 0 : SYMBOL(QueryString),
421 0 : SYMBOL(QueryContext),
422 0 : SYMBOL(BindTexImage),
423 0 : SYMBOL(ReleaseTexImage),
424 0 : SYMBOL(QuerySurface),
425 : END_OF_SYMBOLS
426 0 : };
427 :
428 0 : if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, earlySymbols)) {
429 0 : NS_WARNING("Couldn't find required entry points in EGL library (early init)");
430 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_SYM");
431 0 : return false;
432 : }
433 :
434 : {
435 0 : const char internalFuncName[] = "_Z35eglQueryStringImplementationANDROIDPvi";
436 0 : const auto& internalFunc = PR_FindFunctionSymbol(mEGLLibrary, internalFuncName);
437 0 : if (internalFunc) {
438 0 : *(PRFuncPtr*)&mSymbols.fQueryString = internalFunc;
439 : }
440 : }
441 :
442 0 : InitClientExtensions();
443 :
444 : const auto lookupFunction =
445 0 : (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress;
446 :
447 0 : const auto fnLoadSymbols = [&](const GLLibraryLoader::SymLoadStruct* symbols) {
448 0 : if (GLLibraryLoader::LoadSymbols(mEGLLibrary, symbols, lookupFunction))
449 0 : return true;
450 :
451 0 : ClearSymbols(symbols);
452 0 : return false;
453 0 : };
454 :
455 : // Check the ANGLE support the system has
456 0 : nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
457 0 : mIsANGLE = IsExtensionSupported(ANGLE_platform_angle);
458 :
459 0 : EGLDisplay chosenDisplay = nullptr;
460 :
461 : // Client exts are ready. (But not display exts!)
462 :
463 0 : if (mIsANGLE) {
464 0 : MOZ_ASSERT(IsExtensionSupported(ANGLE_platform_angle_d3d));
465 : const GLLibraryLoader::SymLoadStruct angleSymbols[] = {
466 0 : { (PRFuncPtr*)&mSymbols.fANGLEPlatformInitialize, { "ANGLEPlatformInitialize", nullptr } },
467 0 : { (PRFuncPtr*)&mSymbols.fANGLEPlatformShutdown, { "ANGLEPlatformShutdown", nullptr } },
468 0 : SYMBOL(GetPlatformDisplayEXT),
469 : END_OF_SYMBOLS
470 0 : };
471 0 : if (!fnLoadSymbols(angleSymbols)) {
472 0 : gfxCriticalError() << "Failed to load ANGLE symbols!";
473 0 : return false;
474 : }
475 : }
476 :
477 0 : if (IsExtensionSupported(ANGLE_platform_angle_d3d)) {
478 0 : nsCString accelAngleFailureId;
479 0 : bool accelAngleSupport = IsAccelAngleSupported(gfxInfo, &accelAngleFailureId);
480 0 : bool shouldTryAccel = forceAccel || accelAngleSupport;
481 0 : bool shouldTryWARP = !forceAccel; // Only if ANGLE not supported or fails
482 :
483 : // If WARP preferred, will override ANGLE support
484 0 : if (gfxPrefs::WebGLANGLEForceWARP()) {
485 0 : shouldTryWARP = true;
486 0 : shouldTryAccel = false;
487 0 : if (accelAngleFailureId.IsEmpty()) {
488 0 : accelAngleFailureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_FORCE_WARP");
489 : }
490 : }
491 :
492 : // Hardware accelerated ANGLE path (supported or force accel)
493 0 : if (shouldTryAccel) {
494 0 : chosenDisplay = GetAndInitDisplayForAccelANGLE(*this, out_failureId);
495 : }
496 :
497 : // Report the acceleration status to telemetry
498 0 : if (!chosenDisplay) {
499 0 : if (accelAngleFailureId.IsEmpty()) {
500 0 : Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
501 0 : NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"));
502 : } else {
503 : Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
504 0 : accelAngleFailureId);
505 : }
506 : } else {
507 0 : Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
508 0 : NS_LITERAL_CSTRING("SUCCESS"));
509 : }
510 :
511 : // Fallback to a WARP display if ANGLE fails, or if WARP is forced
512 0 : if (!chosenDisplay && shouldTryWARP) {
513 0 : chosenDisplay = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY);
514 0 : if (!chosenDisplay) {
515 0 : if (out_failureId->IsEmpty()) {
516 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WARP_FALLBACK");
517 : }
518 0 : NS_ERROR("Fallback WARP context failed to initialize.");
519 0 : return false;
520 : }
521 0 : mIsWARP = true;
522 : }
523 : } else {
524 0 : chosenDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY);
525 : }
526 :
527 0 : if (!chosenDisplay) {
528 0 : if (out_failureId->IsEmpty()) {
529 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_DISPLAY");
530 : }
531 0 : NS_WARNING("Failed to initialize a display.");
532 0 : return false;
533 : }
534 0 : mEGLDisplay = chosenDisplay;
535 :
536 0 : InitDisplayExtensions();
537 :
538 : ////////////////////////////////////
539 : // Alright, load display exts.
540 :
541 0 : if (IsExtensionSupported(KHR_lock_surface)) {
542 : const GLLibraryLoader::SymLoadStruct lockSymbols[] = {
543 0 : SYMBOL(LockSurfaceKHR),
544 0 : SYMBOL(UnlockSurfaceKHR),
545 : END_OF_SYMBOLS
546 0 : };
547 0 : if (!fnLoadSymbols(lockSymbols)) {
548 0 : NS_ERROR("EGL supports KHR_lock_surface without exposing its functions!");
549 0 : MarkExtensionUnsupported(KHR_lock_surface);
550 : }
551 : }
552 :
553 0 : if (IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle)) {
554 : const GLLibraryLoader::SymLoadStruct d3dSymbols[] = {
555 0 : SYMBOL(QuerySurfacePointerANGLE),
556 : END_OF_SYMBOLS
557 0 : };
558 0 : if (!fnLoadSymbols(d3dSymbols)) {
559 0 : NS_ERROR("EGL supports ANGLE_surface_d3d_texture_2d_share_handle without exposing its functions!");
560 0 : MarkExtensionUnsupported(ANGLE_surface_d3d_texture_2d_share_handle);
561 : }
562 : }
563 :
564 0 : if (IsExtensionSupported(KHR_fence_sync)) {
565 : const GLLibraryLoader::SymLoadStruct syncSymbols[] = {
566 0 : SYMBOL(CreateSyncKHR),
567 0 : SYMBOL(DestroySyncKHR),
568 0 : SYMBOL(ClientWaitSyncKHR),
569 0 : SYMBOL(GetSyncAttribKHR),
570 : END_OF_SYMBOLS
571 0 : };
572 0 : if (!fnLoadSymbols(syncSymbols)) {
573 0 : NS_ERROR("EGL supports KHR_fence_sync without exposing its functions!");
574 0 : MarkExtensionUnsupported(KHR_fence_sync);
575 : }
576 : }
577 :
578 0 : if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) {
579 : const GLLibraryLoader::SymLoadStruct imageSymbols[] = {
580 0 : SYMBOL(CreateImageKHR),
581 0 : SYMBOL(DestroyImageKHR),
582 : END_OF_SYMBOLS
583 0 : };
584 0 : if (!fnLoadSymbols(imageSymbols)) {
585 0 : NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!");
586 0 : MarkExtensionUnsupported(KHR_image);
587 0 : MarkExtensionUnsupported(KHR_image_base);
588 0 : MarkExtensionUnsupported(KHR_image_pixmap);
589 : }
590 : } else {
591 0 : MarkExtensionUnsupported(KHR_image_pixmap);
592 : }
593 :
594 0 : if (IsExtensionSupported(ANDROID_native_fence_sync)) {
595 : const GLLibraryLoader::SymLoadStruct nativeFenceSymbols[] = {
596 0 : SYMBOL(DupNativeFenceFDANDROID),
597 : END_OF_SYMBOLS
598 0 : };
599 0 : if (!fnLoadSymbols(nativeFenceSymbols)) {
600 0 : NS_ERROR("EGL supports ANDROID_native_fence_sync without exposing its functions!");
601 0 : MarkExtensionUnsupported(ANDROID_native_fence_sync);
602 : }
603 : }
604 :
605 0 : if (IsExtensionSupported(KHR_stream)) {
606 : const GLLibraryLoader::SymLoadStruct streamSymbols[] = {
607 0 : SYMBOL(CreateStreamKHR),
608 0 : SYMBOL(DestroyStreamKHR),
609 0 : SYMBOL(QueryStreamKHR),
610 : END_OF_SYMBOLS
611 0 : };
612 0 : if (!fnLoadSymbols(streamSymbols)) {
613 0 : NS_ERROR("EGL supports KHR_stream without exposing its functions!");
614 0 : MarkExtensionUnsupported(KHR_stream);
615 : }
616 : }
617 :
618 0 : if (IsExtensionSupported(KHR_stream_consumer_gltexture)) {
619 : const GLLibraryLoader::SymLoadStruct streamConsumerSymbols[] = {
620 0 : SYMBOL(StreamConsumerAcquireKHR),
621 0 : SYMBOL(StreamConsumerReleaseKHR),
622 : END_OF_SYMBOLS
623 0 : };
624 0 : if (!fnLoadSymbols(streamConsumerSymbols)) {
625 0 : NS_ERROR("EGL supports KHR_stream_consumer_gltexture without exposing its functions!");
626 0 : MarkExtensionUnsupported(KHR_stream_consumer_gltexture);
627 : }
628 : }
629 :
630 0 : if (IsExtensionSupported(EXT_device_base)) {
631 : const GLLibraryLoader::SymLoadStruct deviceBaseSymbols[] = {
632 0 : SYMBOL(QueryDisplayAttribEXT),
633 : END_OF_SYMBOLS
634 0 : };
635 0 : if (!fnLoadSymbols(deviceBaseSymbols)) {
636 0 : NS_ERROR("EGL supports EXT_device_base without exposing its functions!");
637 0 : MarkExtensionUnsupported(EXT_device_base);
638 : }
639 : }
640 :
641 0 : if (IsExtensionSupported(EXT_device_query)) {
642 : const GLLibraryLoader::SymLoadStruct queryDisplaySymbols[] = {
643 0 : SYMBOL(QueryDeviceAttribEXT),
644 : END_OF_SYMBOLS
645 0 : };
646 0 : if (!fnLoadSymbols(queryDisplaySymbols)) {
647 0 : NS_ERROR("EGL supports EXT_device_query without exposing its functions!");
648 0 : MarkExtensionUnsupported(EXT_device_query);
649 : }
650 : }
651 :
652 0 : if (IsExtensionSupported(NV_stream_consumer_gltexture_yuv)) {
653 : const GLLibraryLoader::SymLoadStruct nvStreamSymbols[] = {
654 0 : SYMBOL(StreamConsumerGLTextureExternalAttribsNV),
655 : END_OF_SYMBOLS
656 0 : };
657 0 : if (!fnLoadSymbols(nvStreamSymbols)) {
658 0 : NS_ERROR("EGL supports NV_stream_consumer_gltexture_yuv without exposing its functions!");
659 0 : MarkExtensionUnsupported(NV_stream_consumer_gltexture_yuv);
660 : }
661 : }
662 :
663 0 : if (IsExtensionSupported(ANGLE_stream_producer_d3d_texture_nv12)) {
664 : const GLLibraryLoader::SymLoadStruct nvStreamSymbols[] = {
665 0 : SYMBOL(CreateStreamProducerD3DTextureNV12ANGLE),
666 0 : SYMBOL(StreamPostD3DTextureNV12ANGLE),
667 : END_OF_SYMBOLS
668 0 : };
669 0 : if (!fnLoadSymbols(nvStreamSymbols)) {
670 0 : NS_ERROR("EGL supports ANGLE_stream_producer_d3d_texture_nv12 without exposing its functions!");
671 0 : MarkExtensionUnsupported(ANGLE_stream_producer_d3d_texture_nv12);
672 : }
673 : }
674 :
675 0 : mInitialized = true;
676 0 : reporter.SetSuccessful();
677 0 : return true;
678 : }
679 :
680 : #undef SYMBOL
681 : #undef END_OF_SYMBOLS
682 :
683 : template<size_t N>
684 : static void
685 0 : MarkExtensions(const char* rawExtString, bool shouldDumpExts, const char* extType,
686 : std::bitset<N>* const out)
687 : {
688 0 : MOZ_ASSERT(rawExtString);
689 :
690 0 : const nsDependentCString extString(rawExtString);
691 :
692 0 : std::vector<nsCString> extList;
693 0 : SplitByChar(extString, ' ', &extList);
694 :
695 0 : if (shouldDumpExts) {
696 0 : printf_stderr("%u EGL %s extensions: (*: recognized)\n",
697 0 : (uint32_t)extList.size(), extType);
698 : }
699 :
700 0 : MarkBitfieldByStrings(extList, shouldDumpExts, sEGLExtensionNames, out);
701 0 : }
702 :
703 : void
704 0 : GLLibraryEGL::InitClientExtensions()
705 : {
706 0 : const bool shouldDumpExts = GLContext::ShouldDumpExts();
707 :
708 0 : const char* rawExtString = nullptr;
709 :
710 : #ifndef ANDROID
711 : // Bug 1209612: Crashes on a number of android drivers.
712 : // Ideally we would only blocklist this there, but for now we don't need the client
713 : // extension list on ANDROID (we mostly need it on ANGLE), and we'd rather not crash.
714 0 : rawExtString = (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS);
715 : #endif
716 :
717 0 : if (!rawExtString) {
718 0 : if (shouldDumpExts) {
719 0 : printf_stderr("No EGL client extensions.\n");
720 : }
721 0 : return;
722 : }
723 :
724 0 : MarkExtensions(rawExtString, shouldDumpExts, "client", &mAvailableExtensions);
725 : }
726 :
727 : void
728 0 : GLLibraryEGL::InitDisplayExtensions()
729 : {
730 0 : MOZ_ASSERT(mEGLDisplay);
731 :
732 0 : const bool shouldDumpExts = GLContext::ShouldDumpExts();
733 :
734 0 : const auto rawExtString = (const char*)fQueryString(mEGLDisplay,
735 0 : LOCAL_EGL_EXTENSIONS);
736 0 : if (!rawExtString) {
737 0 : NS_WARNING("Failed to query EGL display extensions!.");
738 0 : return;
739 : }
740 :
741 0 : MarkExtensions(rawExtString, shouldDumpExts, "display", &mAvailableExtensions);
742 : }
743 :
744 : void
745 0 : GLLibraryEGL::DumpEGLConfig(EGLConfig cfg)
746 : {
747 : int attrval;
748 : int err;
749 :
750 : #define ATTR(_x) do { \
751 : fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
752 : if ((err = fGetError()) != 0x3000) { \
753 : printf_stderr(" %s: ERROR (0x%04x)\n", #_x, err); \
754 : } else { \
755 : printf_stderr(" %s: %d (0x%04x)\n", #_x, attrval, attrval); \
756 : } \
757 : } while(0)
758 :
759 0 : printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg);
760 :
761 0 : ATTR(BUFFER_SIZE);
762 0 : ATTR(ALPHA_SIZE);
763 0 : ATTR(BLUE_SIZE);
764 0 : ATTR(GREEN_SIZE);
765 0 : ATTR(RED_SIZE);
766 0 : ATTR(DEPTH_SIZE);
767 0 : ATTR(STENCIL_SIZE);
768 0 : ATTR(CONFIG_CAVEAT);
769 0 : ATTR(CONFIG_ID);
770 0 : ATTR(LEVEL);
771 0 : ATTR(MAX_PBUFFER_HEIGHT);
772 0 : ATTR(MAX_PBUFFER_PIXELS);
773 0 : ATTR(MAX_PBUFFER_WIDTH);
774 0 : ATTR(NATIVE_RENDERABLE);
775 0 : ATTR(NATIVE_VISUAL_ID);
776 0 : ATTR(NATIVE_VISUAL_TYPE);
777 0 : ATTR(PRESERVED_RESOURCES);
778 0 : ATTR(SAMPLES);
779 0 : ATTR(SAMPLE_BUFFERS);
780 0 : ATTR(SURFACE_TYPE);
781 0 : ATTR(TRANSPARENT_TYPE);
782 0 : ATTR(TRANSPARENT_RED_VALUE);
783 0 : ATTR(TRANSPARENT_GREEN_VALUE);
784 0 : ATTR(TRANSPARENT_BLUE_VALUE);
785 0 : ATTR(BIND_TO_TEXTURE_RGB);
786 0 : ATTR(BIND_TO_TEXTURE_RGBA);
787 0 : ATTR(MIN_SWAP_INTERVAL);
788 0 : ATTR(MAX_SWAP_INTERVAL);
789 0 : ATTR(LUMINANCE_SIZE);
790 0 : ATTR(ALPHA_MASK_SIZE);
791 0 : ATTR(COLOR_BUFFER_TYPE);
792 0 : ATTR(RENDERABLE_TYPE);
793 0 : ATTR(CONFORMANT);
794 :
795 : #undef ATTR
796 0 : }
797 :
798 : void
799 0 : GLLibraryEGL::DumpEGLConfigs()
800 : {
801 0 : int nc = 0;
802 0 : fGetConfigs(mEGLDisplay, nullptr, 0, &nc);
803 0 : EGLConfig* ec = new EGLConfig[nc];
804 0 : fGetConfigs(mEGLDisplay, ec, nc, &nc);
805 :
806 0 : for (int i = 0; i < nc; ++i) {
807 0 : printf_stderr("========= EGL Config %d ========\n", i);
808 0 : DumpEGLConfig(ec[i]);
809 : }
810 :
811 0 : delete [] ec;
812 0 : }
813 :
814 : static bool
815 0 : ShouldTrace()
816 : {
817 0 : static bool ret = gfxEnv::GlDebugVerbose();
818 0 : return ret;
819 : }
820 :
821 : void
822 0 : BeforeEGLCall(const char* glFunction)
823 : {
824 0 : if (ShouldTrace()) {
825 0 : printf_stderr("[egl] > %s\n", glFunction);
826 : }
827 0 : }
828 :
829 : void
830 0 : AfterEGLCall(const char* glFunction)
831 : {
832 0 : if (ShouldTrace()) {
833 0 : printf_stderr("[egl] < %s\n", glFunction);
834 : }
835 0 : }
836 :
837 : } /* namespace gl */
838 : } /* namespace mozilla */
839 :
|