1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/gfx/gfxConfigManager.h"
8 #include "mozilla/gfx/gfxVars.h"
9 #include "mozilla/Preferences.h"
10 #include "mozilla/Components.h"
11 #include "mozilla/StaticPrefs_gfx.h"
12 #include "mozilla/StaticPrefs_layers.h"
13 #include "gfxConfig.h"
14 #include "gfxPlatform.h"
15 #include "nsIGfxInfo.h"
16 #include "nsPrintfCString.h"
17 #include "nsXULAppAPI.h"
18
19 #ifdef XP_WIN
20 # include "mozilla/WindowsVersion.h"
21 # include "mozilla/gfx/DeviceManagerDx.h"
22 # include "mozilla/gfx/DisplayConfigWindows.h"
23 #endif
24
25 namespace mozilla {
26 namespace gfx {
27
Init()28 void gfxConfigManager::Init() {
29 MOZ_ASSERT(XRE_IsParentProcess());
30
31 EmplaceUserPref("gfx.webrender.compositor", mWrCompositorEnabled);
32 mWrForceEnabled = gfxPlatform::WebRenderPrefEnabled();
33 mWrForceDisabled = StaticPrefs::gfx_webrender_force_disabled_AtStartup();
34 mWrSoftwareForceEnabled = StaticPrefs::gfx_webrender_software_AtStartup();
35 mWrCompositorForceEnabled =
36 StaticPrefs::gfx_webrender_compositor_force_enabled_AtStartup();
37 mGPUProcessAllowSoftware =
38 StaticPrefs::layers_gpu_process_allow_software_AtStartup();
39 mWrPartialPresent =
40 StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup() > 0;
41 EmplaceUserPref(StaticPrefs::GetPrefName_gfx_webrender_program_binary_disk(),
42 mWrShaderCache);
43 mWrOptimizedShaders =
44 StaticPrefs::gfx_webrender_use_optimized_shaders_AtStartup();
45 #ifdef XP_WIN
46 mWrForceAngle = StaticPrefs::gfx_webrender_force_angle_AtStartup();
47 mWrForceAngleNoGPUProcess = StaticPrefs::
48 gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup();
49 mWrDCompWinEnabled =
50 Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false);
51 #endif
52
53 mWrEnvForceEnabled = gfxPlatform::WebRenderEnvvarEnabled();
54 mWrEnvForceDisabled = gfxPlatform::WebRenderEnvvarDisabled();
55
56 #ifdef XP_WIN
57 DeviceManagerDx::Get()->CheckHardwareStretchingSupport(mHwStretchingSupport);
58 mScaledResolution = HasScaledResolution();
59 mIsWin10OrLater = IsWin10OrLater();
60 mWrCompositorDCompRequired = true;
61 #else
62 ++mHwStretchingSupport.mBoth;
63 #endif
64
65 #ifdef MOZ_WIDGET_GTK
66 mDisableHwCompositingNoWr = true;
67 mXRenderEnabled = mozilla::Preferences::GetBool("gfx.xrender.enabled");
68 #endif
69
70 #ifdef NIGHTLY_BUILD
71 mIsNightly = true;
72 #endif
73 #ifdef EARLY_BETA_OR_EARLIER
74 mIsEarlyBetaOrEarlier = true;
75 #endif
76 mSafeMode = gfxPlatform::InSafeMode();
77
78 mGfxInfo = components::GfxInfo::Service();
79
80 mFeatureWr = &gfxConfig::GetFeature(Feature::WEBRENDER);
81 mFeatureWrQualified = &gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
82 mFeatureWrCompositor = &gfxConfig::GetFeature(Feature::WEBRENDER_COMPOSITOR);
83 mFeatureWrAngle = &gfxConfig::GetFeature(Feature::WEBRENDER_ANGLE);
84 mFeatureWrDComp = &gfxConfig::GetFeature(Feature::WEBRENDER_DCOMP_PRESENT);
85 mFeatureWrPartial = &gfxConfig::GetFeature(Feature::WEBRENDER_PARTIAL);
86 mFeatureWrShaderCache =
87 &gfxConfig::GetFeature(Feature::WEBRENDER_SHADER_CACHE);
88 mFeatureWrOptimizedShaders =
89 &gfxConfig::GetFeature(Feature::WEBRENDER_OPTIMIZED_SHADERS);
90 mFeatureWrSoftware = &gfxConfig::GetFeature(Feature::WEBRENDER_SOFTWARE);
91
92 mFeatureHwCompositing = &gfxConfig::GetFeature(Feature::HW_COMPOSITING);
93 #ifdef XP_WIN
94 mFeatureD3D11HwAngle = &gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
95 mFeatureD3D11Compositing = &gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
96 #endif
97 mFeatureGPUProcess = &gfxConfig::GetFeature(Feature::GPU_PROCESS);
98 }
99
EmplaceUserPref(const char * aPrefName,Maybe<bool> & aValue)100 void gfxConfigManager::EmplaceUserPref(const char* aPrefName,
101 Maybe<bool>& aValue) {
102 if (Preferences::HasUserValue(aPrefName)) {
103 aValue.emplace(Preferences::GetBool(aPrefName, false));
104 }
105 }
106
ConfigureFromBlocklist(long aFeature,FeatureState * aFeatureState)107 void gfxConfigManager::ConfigureFromBlocklist(long aFeature,
108 FeatureState* aFeatureState) {
109 MOZ_ASSERT(aFeatureState);
110
111 nsCString blockId;
112 int32_t status;
113 if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
114 aFeatureState->Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
115 "FEATURE_FAILURE_NO_GFX_INFO"_ns);
116
117 } else {
118 if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
119 aFeatureState->Disable(FeatureStatus::Blocklisted,
120 "Blocklisted by gfxInfo", blockId);
121 }
122 }
123 }
124
ConfigureWebRenderSoftware()125 void gfxConfigManager::ConfigureWebRenderSoftware() {
126 MOZ_ASSERT(mFeatureWrSoftware);
127
128 mFeatureWrSoftware->EnableByDefault();
129
130 // Note that for testing in CI, software WebRender uses gfx.webrender.software
131 // to force enable WebRender Software. As a result, we need to prefer that
132 // over the MOZ_WEBRENDER envvar which is used to otherwise force on WebRender
133 // (hardware). See bug 1656811.
134 if (mWrSoftwareForceEnabled) {
135 mFeatureWrSoftware->UserForceEnable("Force enabled by pref");
136 } else if (mWrForceDisabled || mWrEnvForceDisabled) {
137 // If the user set the pref to force-disable, let's do that. This
138 // will override all the other enabling prefs
139 mFeatureWrSoftware->UserDisable("User force-disabled WR",
140 "FEATURE_FAILURE_USER_FORCE_DISABLED"_ns);
141 } else if (gfxPlatform::DoesFissionForceWebRender()) {
142 mFeatureWrSoftware->UserForceEnable("Force enabled by fission");
143 }
144
145 if (!mHasWrSoftwareBlocklist) {
146 return;
147 }
148
149 nsCString failureId;
150 int32_t status;
151 if (NS_FAILED(mGfxInfo->GetFeatureStatus(
152 nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE, failureId, &status))) {
153 mFeatureWrSoftware->Disable(FeatureStatus::BlockedNoGfxInfo,
154 "gfxInfo is broken",
155 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
156 return;
157 }
158
159 switch (status) {
160 case nsIGfxInfo::FEATURE_ALLOW_ALWAYS:
161 case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED:
162 break;
163 case nsIGfxInfo::FEATURE_DENIED:
164 mFeatureWrSoftware->Disable(FeatureStatus::Denied, "Not on allowlist",
165 failureId);
166 break;
167 default:
168 mFeatureWrSoftware->Disable(FeatureStatus::Blocklisted,
169 "No qualified hardware", failureId);
170 break;
171 case nsIGfxInfo::FEATURE_STATUS_OK:
172 MOZ_ASSERT_UNREACHABLE("We should still be rolling out WebRender!");
173 mFeatureWrSoftware->Disable(FeatureStatus::Blocked,
174 "Not controlled by rollout", failureId);
175 break;
176 }
177 }
178
ConfigureWebRenderQualified()179 void gfxConfigManager::ConfigureWebRenderQualified() {
180 MOZ_ASSERT(mFeatureWrQualified);
181 MOZ_ASSERT(mFeatureWrCompositor);
182
183 mFeatureWrQualified->EnableByDefault();
184
185 nsCString failureId;
186 int32_t status;
187 if (NS_FAILED(mGfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER,
188 failureId, &status))) {
189 mFeatureWrQualified->Disable(FeatureStatus::BlockedNoGfxInfo,
190 "gfxInfo is broken",
191 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
192 return;
193 }
194
195 switch (status) {
196 case nsIGfxInfo::FEATURE_ALLOW_ALWAYS:
197 case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED:
198 break;
199 case nsIGfxInfo::FEATURE_DENIED:
200 mFeatureWrQualified->Disable(FeatureStatus::Denied, "Not on allowlist",
201 failureId);
202 break;
203 default:
204 mFeatureWrQualified->Disable(FeatureStatus::Blocklisted,
205 "No qualified hardware", failureId);
206 break;
207 case nsIGfxInfo::FEATURE_STATUS_OK:
208 MOZ_ASSERT_UNREACHABLE("We should still be rolling out WebRender!");
209 mFeatureWrQualified->Disable(FeatureStatus::Blocked,
210 "Not controlled by rollout", failureId);
211 break;
212 }
213 }
214
ConfigureWebRender()215 void gfxConfigManager::ConfigureWebRender() {
216 MOZ_ASSERT(XRE_IsParentProcess());
217 MOZ_ASSERT(mFeatureWr);
218 MOZ_ASSERT(mFeatureWrQualified);
219 MOZ_ASSERT(mFeatureWrCompositor);
220 MOZ_ASSERT(mFeatureWrAngle);
221 MOZ_ASSERT(mFeatureWrDComp);
222 MOZ_ASSERT(mFeatureWrPartial);
223 MOZ_ASSERT(mFeatureWrShaderCache);
224 MOZ_ASSERT(mFeatureWrOptimizedShaders);
225 MOZ_ASSERT(mFeatureWrSoftware);
226 MOZ_ASSERT(mFeatureHwCompositing);
227 MOZ_ASSERT(mFeatureGPUProcess);
228
229 // Initialize WebRender native compositor usage
230 mFeatureWrCompositor->SetDefaultFromPref("gfx.webrender.compositor", true,
231 false, mWrCompositorEnabled);
232
233 if (mWrCompositorForceEnabled) {
234 mFeatureWrCompositor->UserForceEnable("Force enabled by pref");
235 }
236
237 ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
238 mFeatureWrCompositor);
239
240 // Disable native compositor when hardware stretching is not supported. It is
241 // for avoiding a problem like Bug 1618370.
242 // XXX Is there a better check for Bug 1618370?
243 if (!mHwStretchingSupport.IsFullySupported() && mScaledResolution) {
244 nsPrintfCString failureId(
245 "FEATURE_FAILURE_NO_HARDWARE_STRETCHING_B%uW%uF%uN%uE%u",
246 mHwStretchingSupport.mBoth, mHwStretchingSupport.mWindowOnly,
247 mHwStretchingSupport.mFullScreenOnly, mHwStretchingSupport.mNone,
248 mHwStretchingSupport.mError);
249 mFeatureWrCompositor->Disable(FeatureStatus::Unavailable,
250 "No hardware stretching support", failureId);
251 }
252
253 ConfigureWebRenderSoftware();
254 ConfigureWebRenderQualified();
255
256 mFeatureWr->EnableByDefault();
257
258 // envvar works everywhere; note that we need this for testing in CI.
259 // Prior to bug 1523788, the `prefEnabled` check was only done on Nightly,
260 // so as to prevent random users from easily enabling WebRender on
261 // unqualified hardware in beta/release.
262 if (mWrSoftwareForceEnabled) {
263 MOZ_ASSERT(mFeatureWrSoftware->IsEnabled());
264 mFeatureWr->UserDisable("User force-enabled software WR",
265 "FEATURE_FAILURE_USER_FORCE_ENABLED_SW_WR"_ns);
266 } else if (mWrEnvForceEnabled) {
267 mFeatureWr->UserForceEnable("Force enabled by envvar");
268 } else if (mWrForceDisabled || mWrEnvForceDisabled) {
269 // If the user set the pref to force-disable, let's do that. This
270 // will override all the other enabling prefs
271 // (gfx.webrender.enabled, gfx.webrender.all, and
272 // gfx.webrender.all.qualified).
273 mFeatureWr->UserDisable("User force-disabled WR",
274 "FEATURE_FAILURE_USER_FORCE_DISABLED"_ns);
275 } else if (mWrForceEnabled) {
276 mFeatureWr->UserForceEnable("Force enabled by pref");
277 }
278
279 if (!mFeatureWrQualified->IsEnabled()) {
280 // No qualified hardware. If we haven't allowed software fallback,
281 // then we need to disable WR.
282 mFeatureWr->Disable(FeatureStatus::Disabled, "Not qualified",
283 "FEATURE_FAILURE_NOT_QUALIFIED"_ns);
284 }
285
286 // HW_COMPOSITING being disabled implies interfacing with the GPU might break
287 if (!mFeatureHwCompositing->IsEnabled()) {
288 mFeatureWr->ForceDisable(FeatureStatus::UnavailableNoHwCompositing,
289 "Hardware compositing is disabled",
290 "FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"_ns);
291 }
292
293 if (mSafeMode) {
294 mFeatureWr->ForceDisable(FeatureStatus::UnavailableInSafeMode,
295 "Safe-mode is enabled",
296 "FEATURE_FAILURE_SAFE_MODE"_ns);
297 mFeatureWrSoftware->ForceDisable(FeatureStatus::UnavailableInSafeMode,
298 "Safe-mode is enabled",
299 "FEATURE_FAILURE_SAFE_MODE"_ns);
300 }
301
302 if (mXRenderEnabled) {
303 // XRender and WebRender don't play well together. XRender is disabled by
304 // default. If the user opts into it don't enable webrender.
305 mFeatureWr->ForceDisable(FeatureStatus::Blocked, "XRender is enabled",
306 "FEATURE_FAILURE_XRENDER"_ns);
307 mFeatureWrSoftware->ForceDisable(FeatureStatus::Blocked,
308 "XRender is enabled",
309 "FEATURE_FAILURE_XRENDER"_ns);
310 }
311
312 mFeatureWrAngle->EnableByDefault();
313 if (mFeatureD3D11HwAngle) {
314 if (mWrForceAngle) {
315 if (!mFeatureD3D11HwAngle->IsEnabled()) {
316 mFeatureWrAngle->ForceDisable(FeatureStatus::UnavailableNoAngle,
317 "ANGLE is disabled",
318 mFeatureD3D11HwAngle->GetFailureId());
319 } else if (!mFeatureGPUProcess->IsEnabled() &&
320 !mWrForceAngleNoGPUProcess) {
321 // WebRender with ANGLE relies on the GPU process when on Windows
322 mFeatureWrAngle->ForceDisable(
323 FeatureStatus::UnavailableNoGpuProcess, "GPU Process is disabled",
324 "FEATURE_FAILURE_GPU_PROCESS_DISABLED"_ns);
325 } else if (!mFeatureWr->IsEnabled() && !mFeatureWrSoftware->IsEnabled()) {
326 mFeatureWrAngle->ForceDisable(FeatureStatus::Unavailable,
327 "WebRender disabled",
328 "FEATURE_FAILURE_WR_DISABLED"_ns);
329 }
330 } else {
331 mFeatureWrAngle->Disable(FeatureStatus::Disabled, "ANGLE is not forced",
332 "FEATURE_FAILURE_ANGLE_NOT_FORCED"_ns);
333 }
334 } else {
335 mFeatureWrAngle->Disable(FeatureStatus::Unavailable, "OS not supported",
336 "FEATURE_FAILURE_OS_NOT_SUPPORTED"_ns);
337 }
338
339 if (mWrForceAngle && mFeatureWr->IsEnabled() &&
340 !mFeatureWrAngle->IsEnabled()) {
341 // Ensure we disable WebRender if ANGLE is unavailable and it is required.
342 mFeatureWr->ForceDisable(FeatureStatus::UnavailableNoAngle,
343 "ANGLE is disabled",
344 mFeatureWrAngle->GetFailureId());
345 }
346
347 if (!mFeatureWr->IsEnabled() && mDisableHwCompositingNoWr) {
348 if (mFeatureHwCompositing->IsEnabled()) {
349 // Hardware compositing should be disabled by default if we aren't using
350 // WebRender. We had to check if it is enabled at all, because it may
351 // already have been forced disabled (e.g. safe mode, headless). It may
352 // still be forced on by the user, and if so, this should have no effect.
353 mFeatureHwCompositing->Disable(FeatureStatus::Blocked,
354 "Acceleration blocked by platform", ""_ns);
355 }
356
357 if (!mFeatureHwCompositing->IsEnabled() &&
358 mFeatureGPUProcess->IsEnabled() && !mGPUProcessAllowSoftware) {
359 // We have neither WebRender nor OpenGL, we don't allow the GPU process
360 // for basic compositor, and it wasn't disabled already.
361 mFeatureGPUProcess->Disable(FeatureStatus::Unavailable,
362 "Hardware compositing is unavailable.",
363 ""_ns);
364 }
365 }
366
367 mFeatureWrDComp->EnableByDefault();
368 if (!mWrDCompWinEnabled) {
369 mFeatureWrDComp->UserDisable("User disabled via pref",
370 "FEATURE_FAILURE_DCOMP_PREF_DISABLED"_ns);
371 }
372
373 if (!mIsWin10OrLater) {
374 // XXX relax win version to windows 8.
375 mFeatureWrDComp->Disable(FeatureStatus::Unavailable,
376 "Requires Windows 10 or later",
377 "FEATURE_FAILURE_DCOMP_NOT_WIN10"_ns);
378 }
379
380 if (!mIsNightly) {
381 // Disable DirectComposition for NVIDIA users with high/mixed refresh rate
382 // monitors due to rendering artifacts.
383 nsAutoString adapterVendorID;
384 mGfxInfo->GetAdapterVendorID(adapterVendorID);
385 if (adapterVendorID == u"0x10de") {
386 bool mixed = false;
387 int32_t maxRefreshRate = mGfxInfo->GetMaxRefreshRate(&mixed);
388 if (maxRefreshRate > 60 && mixed) {
389 mFeatureWrDComp->Disable(FeatureStatus::Blocked,
390 "Monitor refresh rate too high/mixed",
391 "NVIDIA_REFRESH_RATE_MIXED"_ns);
392 }
393 }
394 }
395
396 mFeatureWrDComp->MaybeSetFailed(
397 mFeatureWr->IsEnabled(), FeatureStatus::Unavailable, "Requires WebRender",
398 "FEATURE_FAILURE_DCOMP_NOT_WR"_ns);
399 mFeatureWrDComp->MaybeSetFailed(mFeatureWrAngle->IsEnabled(),
400 FeatureStatus::Unavailable, "Requires ANGLE",
401 "FEATURE_FAILURE_DCOMP_NOT_ANGLE"_ns);
402
403 if (!mFeatureWrDComp->IsEnabled() && mWrCompositorDCompRequired) {
404 mFeatureWrCompositor->ForceDisable(FeatureStatus::Unavailable,
405 "No DirectComposition usage",
406 mFeatureWrDComp->GetFailureId());
407 }
408
409 // Initialize WebRender partial present config.
410 // Partial present is used only when WebRender compositor is not used.
411 if (mWrPartialPresent) {
412 if (mFeatureWr->IsEnabled() || mFeatureWrSoftware->IsEnabled()) {
413 mFeatureWrPartial->EnableByDefault();
414
415 nsString adapter;
416 mGfxInfo->GetAdapterDeviceID(adapter);
417 // Block partial present on some devices due to rendering issues.
418 // On Mali-Txxx due to bug 1680087 and bug 1707815.
419 // On Adreno 3xx GPUs due to bug 1695771.
420 if (adapter.Find("Mali-T", /*ignoreCase*/ true) >= 0 ||
421 adapter.Find("Adreno (TM) 3", /*ignoreCase*/ true) >= 0) {
422 mFeatureWrPartial->Disable(
423 FeatureStatus::Blocked, "Partial present blocked",
424 "FEATURE_FAILURE_PARTIAL_PRESENT_BLOCKED"_ns);
425 }
426 }
427 }
428
429 mFeatureWrShaderCache->SetDefaultFromPref(
430 StaticPrefs::GetPrefName_gfx_webrender_program_binary_disk(), true,
431 StaticPrefs::GetPrefDefault_gfx_webrender_program_binary_disk(),
432 mWrShaderCache);
433 ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_SHADER_CACHE,
434 mFeatureWrShaderCache);
435 if (!mFeatureWr->IsEnabled()) {
436 mFeatureWrShaderCache->ForceDisable(FeatureStatus::Unavailable,
437 "WebRender disabled",
438 "FEATURE_FAILURE_WR_DISABLED"_ns);
439 }
440
441 mFeatureWrOptimizedShaders->EnableByDefault();
442 if (!mWrOptimizedShaders) {
443 mFeatureWrOptimizedShaders->UserDisable("User disabled via pref",
444 "FEATURE_FAILURE_PREF_DISABLED"_ns);
445 }
446 ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_OPTIMIZED_SHADERS,
447 mFeatureWrOptimizedShaders);
448 if (!mFeatureWr->IsEnabled()) {
449 mFeatureWrOptimizedShaders->ForceDisable(FeatureStatus::Unavailable,
450 "WebRender disabled",
451 "FEATURE_FAILURE_WR_DISABLED"_ns);
452 }
453 }
454
455 } // namespace gfx
456 } // namespace mozilla
457