List items
Items from the current list are shown below.
Blog
20 Feb 2024 : Day 162 #
Yesterday we were looking in to the WebView rendering pipeline. We got to the point where we had a backtrace showing the flow that resulted in a WebRender layer manager being created, when the EmbedLite code was expecting a Client layer manager. The consequence was that the EmbedLite code forcefully killed itself.
That was on ESR 91. Today I want to find the equivalent flow on ESR 78 to see how it differs. To do this I need to first install the same harbour-webview-example code that I'm using for testing on my ESR 78 device. Then set it off with the debugger:
The options structure and its functionality is defined in CompositorOptions.h. Checking through the code there we can see that mUseWebRender is set at initialisation, either to the default value of false if the default constructor is used, or an explicit value if the following constructor overload is used:
For both ESR 78 and ESR 91, the value that's passed in is that of the local enableWR variable. The logic for this value is really straightforward for ESR 78:
Let's find out which is responsible.
The value of enableWR has a much more complex derivation in ESR 91 compared to that in ESR 78. Here's the logic (note that I've simplified the code to remove the unnecessary parts):
So we have a clear difference. In ESR 78 Feature::WEBRENDER is set to false. In ESR 91 the Feature::WEBRENDER_SOFTWARE has been added which is enough for the WebRender layer manager to be enabled.
This is good progress. The next step is to figure out where Feature::WEBRENDER_SOFTWARE is being set to enabled and find out how to disable it. I'll take a look at that tomorrow.
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
That was on ESR 91. Today I want to find the equivalent flow on ESR 78 to see how it differs. To do this I need to first install the same harbour-webview-example code that I'm using for testing on my ESR 78 device. Then set it off with the debugger:
$ gdb harbour-webview [...] (gdb) b nsBaseWidget::CreateCompositorSession Function "nsBaseWidget::CreateCompositorSession" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (nsBaseWidget::CreateCompositorSession) pending. (gdb) r [...] Thread 7 "GeckoWorkerThre" hit Breakpoint 1, nsBaseWidget:: CreateCompositorSession (this=this@entry=0x7f8ccbf3d0, aWidth=1080, aHeight=2520, aOptionsOut=aOptionsOut@entry=0x7fa7972ac0) at widget/nsBaseWidget.cpp:1176 1176 int aWidth, int aHeight, CompositorOptions* aOptionsOut) { (gdb) n 1180 CreateCompositorVsyncDispatcher(); (gdb) n 1182 gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get(); (gdb) n 1186 gpu->EnsureGPUReady(); (gdb) n 67 obj-build-mer-qt-xr/dist/include/mozilla/StaticPtr.h: No such file or directory. (gdb) n 1193 bool enableAPZ = UseAPZ(); (gdb) n 1194 CompositorOptions options(enableAPZ, enableWR); (gdb) n 1198 bool enableAL = (gdb) n 1203 options.SetUseWebGPU(StaticPrefs::dom_webgpu_enabled()); (gdb) n 50 obj-build-mer-qt-xr/dist/include/mozilla/layers/CompositorOptions.h: No such file or directory. (gdb) n 1210 options.SetInitiallyPaused(CompositorInitiallyPaused()); (gdb) n 53 obj-build-mer-qt-xr/dist/include/mozilla/layers/CompositorOptions.h: No such file or directory. (gdb) 39 in obj-build-mer-qt-xr/dist/include/mozilla/layers/CompositorOptions.h (gdb) 1217 lm = new ClientLayerManager(this); (gdb) p enableWR $1 = false (gdb) p enableAPZ $2 = <optimized out> (gdb) p enableAL $3 = <optimized out> (gdb) p gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS) $4 = false (gdb) p mFissionWindow $5 = false (gdb) p StaticPrefs::layers_advanced_fission_enabled() No symbol "layers_advanced_fission_enabled" in namespace "mozilla::StaticPrefs". (gdb) p StaticPrefs::dom_webgpu_enabled() $6 = false (gdb) p options.UseWebRender() Cannot evaluate function -- may be inlined (gdb) p options $7 = {mUseAPZ = true, mUseWebRender = false, mUseAdvancedLayers = false, mUseWebGPU = false, mInitiallyPaused = false} (gdb)As we can see, on ESR 78 things are different: the options.mUseWebRender field is set to false compared to ESR 91 where it's set to true. What's feeding in to these values?
The options structure and its functionality is defined in CompositorOptions.h. Checking through the code there we can see that mUseWebRender is set at initialisation, either to the default value of false if the default constructor is used, or an explicit value if the following constructor overload is used:
CompositorOptions(bool aUseAPZ, bool aUseWebRender, bool aUseSoftwareWebRender) : mUseAPZ(aUseAPZ), mUseWebRender(aUseWebRender), mUseSoftwareWebRender(aUseSoftwareWebRender) { MOZ_ASSERT_IF(aUseSoftwareWebRender, aUseWebRender); }It's never changed after that. So going back to our nsBaseWidget::CreateCompositorSession() code, the only part we need to concern ourselves with is the value that's passed in to the constructor.
For both ESR 78 and ESR 91, the value that's passed in is that of the local enableWR variable. The logic for this value is really straightforward for ESR 78:
bool enableWR = gfx::gfxVars::UseWebRender() && WidgetTypeSupportsAcceleration();Let's find out how this value is being set:
(gdb) p WidgetTypeSupportsAcceleration() $8 = true (gdb) p gfx::gfxVars::UseWebRender() Cannot evaluate function -- may be inlinedWe can't call the UseWebRender() method directly, but we can extract the value it would return by digging into the data structures. This is all following from the code in gfxVars.h:
(gdb) p gfx::gfxVars::sInstance.mRawPtr.mVarUseWebRender.mValue $11 = falseThat's useful, but it doesn't tell us everything we need to know. The next step is to find out where and why this value is being set to false.
$ grep -rIn "gfxVars::SetUseWebRender(" * --include="*.cpp" gecko-dev/gfx/thebes/gfxPlatform.cpp:2750: gfxVars::SetUseWebRender(true); gecko-dev/gfx/thebes/gfxPlatform.cpp:3297: gfxVars::SetUseWebRender(false); gecko-dev/gfx/ipc/GPUProcessManager.cpp:479: gfx::gfxVars::SetUseWebRender(false);These are being set in gfxPlatform::InitWebRenderConfig(), gfxPlatform::NotifyGPUProcessDisabled() and GPUProcessManager::DisableWebRender() respectively.
Let's find out which is responsible.
(gdb) delete break Delete all breakpoints? (y or n) y (gdb) break gfxPlatform::InitWebRenderConfig Breakpoint 2 at 0x7fb9013328: file gfx/thebes/gfxPlatform.cpp, line 2691. (gdb) b gfxPlatform::NotifyGPUProcessDisabled Breakpoint 3 at 0x7fb9016fb0: file gfx/thebes/gfxPlatform.cpp, line 3291. (gdb) b GPUProcessManager::DisableWebRender Breakpoint 4 at 0x7fb907f858: GPUProcessManager::DisableWebRender. (3 locations) (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /usr/bin/harbour-webview [...] Thread 7 "GeckoWorkerThre" hit Breakpoint 2, gfxPlatform::InitWebRenderConfig (this=0x7f8c8bbf60) at gfx/thebes/gfxPlatform.cpp:2691 2691 void gfxPlatform::InitWebRenderConfig() { (gdb) n 2692 bool prefEnabled = WebRenderPrefEnabled(); (gdb) n 2693 bool envvarEnabled = WebRenderEnvvarEnabled(); (gdb) n 2698 gfxVars::AddReceiver(&nsCSSProps::GfxVarReceiver()); (gdb) n 2708 ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled); (gdb) n 2709 if (!XRE_IsParentProcess()) { (gdb) n 2723 gfxConfigManager manager; (gdb) n 2725 manager.ConfigureWebRender(); (gdb) n 2733 if (Preferences::GetBool("gfx.webrender.program-binary-disk", false)) { (gdb) n 2738 if (StaticPrefs::gfx_webrender_use_optimized_shaders_AtStartup()) { (gdb) n 2739 gfxVars::SetUseWebRenderOptimizedShaders( (gdb) n 2743 if (Preferences::GetBool("gfx.webrender.software", false)) { (gdb) p gfxConfig::IsEnabled(Feature::WEBRENDER) $12 = false (gdb) n 2749 if (gfxConfig::IsEnabled(Feature::WEBRENDER)) { (gdb) n 2791 if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) { (gdb) p gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR) $13 = false (gdb) n 2795 Telemetry::ScalarSet( (gdb) n 2799 if (gfxConfig::IsEnabled(Feature::WEBRENDER_PARTIAL)) { (gdb) n 2805 gfxVars::SetUseGLSwizzle( (gdb) n 2810 gfxUtils::RemoveShaderCacheFromDiskIfNecessary(); (gdb) r [...]No other breakpoints are hit. So as we can see here, on ESR 78 the value for UseWebRender() is left as the default value of false. The reason for this is that gfxConfig::IsEnabled(Feature::WEBRENDER) is returning false. We might need to investigate further where this Feature::WEBRENDER configuration value is coming from or being set, but let's switch to ESR 91 now to find out how things are happening there.
The value of enableWR has a much more complex derivation in ESR 91 compared to that in ESR 78. Here's the logic (note that I've simplified the code to remove the unnecessary parts):
bool supportsAcceleration = WidgetTypeSupportsAcceleration(); bool enableWR; if (supportsAcceleration || StaticPrefs::gfx_webrender_unaccelerated_widget_force()) { enableWR = gfx::gfxVars::UseWebRender(); } else if (gfxPlatform::DoesFissionForceWebRender() || StaticPrefs:: gfx_webrender_software_unaccelerated_widget_allow()) { enableWR = gfx::gfxVars::UseWebRender(); } else { enableWR = false; }In practice supportsAcceleration is going to be set to true, which simplifies things and brings us back to this condition:
enableWR = gfx::gfxVars::UseWebRender();Let's follow the same investigatory path that we did for ESR 78.
$ grep -rIn "gfxVars::SetUseWebRender(" * --include="*.cpp" gecko-dev/gfx/thebes/gfxPlatform.cpp:2713: gfxVars::SetUseWebRender(true); gecko-dev/gfx/thebes/gfxPlatform.cpp:3435: gfxVars::SetUseWebRender(true); gecko-dev/gfx/thebes/gfxPlatform.cpp:3475: gfxVars::SetUseWebRender(false);The second of these appears in some code that's compile-time conditional on the platform being Windows XP, so we can ignore it. The other two appear in gfxPlatform::InitWebRenderConfig() and gfxPlatform::FallbackFromAcceleration() respectively. I'm going to go out on a limb and say that we're interested in the former, but let's check using the debugger to make sure.
(gdb) delete break Delete all breakpoints? (y or n) y (gdb) b gfxPlatform::InitWebRenderConfig Breakpoint 7 at 0x7ff12ef954: file gfx/thebes/gfxPlatform.cpp, line 2646. (gdb) b gfxPlatform::FallbackFromAcceleration Breakpoint 8 at 0x7ff12f3048: file gfx/thebes/gfxPlatform.cpp, line 3381. (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /usr/bin/harbour-webview [...] Thread 7 "GeckoWorkerThre" hit Breakpoint 7, gfxPlatform::InitWebRenderConfig (this=0x7fc4a48c90) at gfx/thebes/gfxPlatform.cpp:2646 2646 void gfxPlatform::InitWebRenderConfig() { (gdb) n 2647 bool prefEnabled = WebRenderPrefEnabled(); (gdb) n 2648 bool envvarEnabled = WebRenderEnvvarEnabled(); (gdb) [New LWP 27297] 2653 gfxVars::AddReceiver(&nsCSSProps::GfxVarReceiver()); (gdb) 2663 ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled); (gdb) 32 ${PROJECT}/obj-build-mer-qt-xr/dist/include/gfxCrashReporterUtils.h: No such file or directory. (gdb) 2664 if (!XRE_IsParentProcess()) { (gdb) 2678 gfxConfigManager manager; (gdb) 2679 manager.Init(); (gdb) 2680 manager.ConfigureWebRender(); (gdb) 2682 bool hasHardware = gfxConfig::IsEnabled(Feature::WEBRENDER); (gdb) 2683 bool hasSoftware = gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE); (gdb) 2684 bool hasWebRender = hasHardware || hasSoftware; (gdb) p hasHardware $10 = false (gdb) p hasSoftware $11 = true (gdb) p hasWebRender $12 = <optimized out> (gdb) n 2701 if (gfxConfig::IsEnabled(Feature::WEBRENDER_SHADER_CACHE)) { (gdb) n 2705 gfxVars::SetUseWebRenderOptimizedShaders( (gdb) n 2708 gfxVars::SetUseSoftwareWebRender(!hasHardware && hasSoftware); (gdb) n 2712 if (hasWebRender) { (gdb) n 2713 gfxVars::SetUseWebRender(true); (gdb) c [...]So there we can see that the WebRender layer manager is being activated in ESR 91 due to Feature::WEBRENDER_SOFTWARE being enabled.
So we have a clear difference. In ESR 78 Feature::WEBRENDER is set to false. In ESR 91 the Feature::WEBRENDER_SOFTWARE has been added which is enough for the WebRender layer manager to be enabled.
This is good progress. The next step is to figure out where Feature::WEBRENDER_SOFTWARE is being set to enabled and find out how to disable it. I'll take a look at that tomorrow.
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
Comments
Uncover Disqus comments