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