summaryrefslogtreecommitdiffstats
path: root/gfx/config/gfxConfigManager.cpp
blob: 644ad3000796c5c89df0ebcd865b606e94a248e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/gfx/gfxConfigManager.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/Preferences.h"
#include "mozilla/Components.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layers.h"
#include "gfxConfig.h"
#include "gfxPlatform.h"
#include "nsIGfxInfo.h"
#include "nsPrintfCString.h"
#include "nsXULAppAPI.h"

#ifdef XP_WIN
#  include "mozilla/WindowsVersion.h"
#  include "mozilla/gfx/DeviceManagerDx.h"
#  include "mozilla/gfx/DisplayConfigWindows.h"
#endif

namespace mozilla {
namespace gfx {

void gfxConfigManager::Init() {
  MOZ_ASSERT(XRE_IsParentProcess());

  EmplaceUserPref("gfx.webrender.compositor", mWrCompositorEnabled);
  mWrForceEnabled = gfxPlatform::WebRenderPrefEnabled();
  mWrSoftwareForceEnabled = StaticPrefs::gfx_webrender_software_AtStartup();
  mWrCompositorForceEnabled =
      StaticPrefs::gfx_webrender_compositor_force_enabled_AtStartup();
  mGPUProcessAllowSoftware =
      StaticPrefs::layers_gpu_process_allow_software_AtStartup();
  mWrForcePartialPresent =
      StaticPrefs::gfx_webrender_force_partial_present_AtStartup();
  mWrPartialPresent =
      StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup() > 0;
  EmplaceUserPref(StaticPrefs::GetPrefName_gfx_webrender_program_binary_disk(),
                  mWrShaderCache);
  mWrOptimizedShaders =
      StaticPrefs::gfx_webrender_use_optimized_shaders_AtStartup();
  mWrScissoredCacheClearsEnabled =
      StaticPrefs::gfx_webrender_scissored_cache_clears_enabled_AtStartup();
  mWrScissoredCacheClearsForceEnabled = StaticPrefs::
      gfx_webrender_scissored_cache_clears_force_enabled_AtStartup();
#ifdef XP_WIN
  mWrForceAngle = StaticPrefs::gfx_webrender_force_angle_AtStartup();
  mWrForceAngleNoGPUProcess = StaticPrefs::
      gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup();
  mWrDCompWinEnabled =
      Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false);
#endif

  mWrEnvForceEnabled = gfxPlatform::WebRenderEnvvarEnabled();

#ifdef XP_WIN
  DeviceManagerDx::Get()->CheckHardwareStretchingSupport(mHwStretchingSupport);
  mScaledResolution = HasScaledResolution();
  mIsWin10OrLater = IsWin10OrLater();
  mIsWin11OrLater = IsWin11OrLater();
  mWrCompositorDCompRequired = true;
#else
  ++mHwStretchingSupport.mBoth;
#endif

#ifdef MOZ_WIDGET_GTK
  mDisableHwCompositingNoWr = true;
#endif

#ifdef NIGHTLY_BUILD
  mIsNightly = true;
#endif
#ifdef EARLY_BETA_OR_EARLIER
  mIsEarlyBetaOrEarlier = true;
#endif
  mSafeMode = gfxPlatform::InSafeMode();

  mGfxInfo = components::GfxInfo::Service();

  mFeatureWr = &gfxConfig::GetFeature(Feature::WEBRENDER);
  mFeatureWrCompositor = &gfxConfig::GetFeature(Feature::WEBRENDER_COMPOSITOR);
  mFeatureWrAngle = &gfxConfig::GetFeature(Feature::WEBRENDER_ANGLE);
  mFeatureWrDComp = &gfxConfig::GetFeature(Feature::WEBRENDER_DCOMP_PRESENT);
  mFeatureWrPartial = &gfxConfig::GetFeature(Feature::WEBRENDER_PARTIAL);
  mFeatureWrShaderCache =
      &gfxConfig::GetFeature(Feature::WEBRENDER_SHADER_CACHE);
  mFeatureWrOptimizedShaders =
      &gfxConfig::GetFeature(Feature::WEBRENDER_OPTIMIZED_SHADERS);
  mFeatureWrScissoredCacheClears =
      &gfxConfig::GetFeature(Feature::WEBRENDER_SCISSORED_CACHE_CLEARS);

  mFeatureHwCompositing = &gfxConfig::GetFeature(Feature::HW_COMPOSITING);
#ifdef XP_WIN
  mFeatureD3D11HwAngle = &gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
  mFeatureD3D11Compositing = &gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
#endif
  mFeatureGPUProcess = &gfxConfig::GetFeature(Feature::GPU_PROCESS);
}

void gfxConfigManager::EmplaceUserPref(const char* aPrefName,
                                       Maybe<bool>& aValue) {
  if (Preferences::HasUserValue(aPrefName)) {
    aValue.emplace(Preferences::GetBool(aPrefName, false));
  }
}

void gfxConfigManager::ConfigureFromBlocklist(long aFeature,
                                              FeatureState* aFeatureState) {
  MOZ_ASSERT(aFeatureState);

  nsCString blockId;
  int32_t status;
  if (!NS_SUCCEEDED(mGfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
    aFeatureState->Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
                           "FEATURE_FAILURE_NO_GFX_INFO"_ns);
    return;
  }

  switch (status) {
    case nsIGfxInfo::FEATURE_STATUS_OK:
    case nsIGfxInfo::FEATURE_ALLOW_ALWAYS:
      break;
    case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED:
      MOZ_ASSERT_UNREACHABLE("Allowing only qualified, but needs experiment?");
      break;
    case nsIGfxInfo::FEATURE_DENIED:
      aFeatureState->Disable(FeatureStatus::Denied, "Not on allowlist",
                             blockId);
      break;
    default:
      aFeatureState->Disable(FeatureStatus::Blocklisted,
                             "Blocklisted by gfxInfo", blockId);
      break;
  }
}

void gfxConfigManager::ConfigureWebRender() {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(mFeatureWr);
  MOZ_ASSERT(mFeatureWrCompositor);
  MOZ_ASSERT(mFeatureWrAngle);
  MOZ_ASSERT(mFeatureWrDComp);
  MOZ_ASSERT(mFeatureWrPartial);
  MOZ_ASSERT(mFeatureWrShaderCache);
  MOZ_ASSERT(mFeatureWrOptimizedShaders);
  MOZ_ASSERT(mFeatureWrScissoredCacheClears);
  MOZ_ASSERT(mFeatureHwCompositing);
  MOZ_ASSERT(mFeatureGPUProcess);

  // Initialize WebRender native compositor usage
  mFeatureWrCompositor->SetDefaultFromPref("gfx.webrender.compositor", true,
                                           false, mWrCompositorEnabled);

  if (mWrCompositorForceEnabled) {
    mFeatureWrCompositor->UserForceEnable("Force enabled by pref");
  }

  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
                         mFeatureWrCompositor);

  // Disable native compositor when hardware stretching is not supported. It is
  // for avoiding a problem like Bug 1618370.
  // XXX Is there a better check for Bug 1618370?
  if (!mHwStretchingSupport.IsFullySupported() && mScaledResolution) {
    nsPrintfCString failureId(
        "FEATURE_FAILURE_NO_HARDWARE_STRETCHING_B%uW%uF%uN%uE%u",
        mHwStretchingSupport.mBoth, mHwStretchingSupport.mWindowOnly,
        mHwStretchingSupport.mFullScreenOnly, mHwStretchingSupport.mNone,
        mHwStretchingSupport.mError);
    mFeatureWrCompositor->Disable(FeatureStatus::Unavailable,
                                  "No hardware stretching support", failureId);
  }

  mFeatureWr->EnableByDefault();

  // envvar works everywhere; note that we need this for testing in CI.
  // Prior to bug 1523788, the `prefEnabled` check was only done on Nightly,
  // so as to prevent random users from easily enabling WebRender on
  // unqualified hardware in beta/release.
  if (mWrSoftwareForceEnabled) {
    mFeatureWr->UserDisable("User force-enabled software WR",
                            "FEATURE_FAILURE_USER_FORCE_ENABLED_SW_WR"_ns);
  } else if (mWrEnvForceEnabled) {
    mFeatureWr->UserForceEnable("Force enabled by envvar");
  } else if (mWrForceEnabled) {
    mFeatureWr->UserForceEnable("Force enabled by pref");
  }

  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER, mFeatureWr);

  // HW_COMPOSITING being disabled implies interfacing with the GPU might break
  if (!mFeatureHwCompositing->IsEnabled()) {
    mFeatureWr->ForceDisable(FeatureStatus::UnavailableNoHwCompositing,
                             "Hardware compositing is disabled",
                             "FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"_ns);
  }

  if (mSafeMode) {
    mFeatureWr->ForceDisable(FeatureStatus::UnavailableInSafeMode,
                             "Safe-mode is enabled",
                             "FEATURE_FAILURE_SAFE_MODE"_ns);
  }

  mFeatureWrAngle->EnableByDefault();
  if (mFeatureD3D11HwAngle) {
    if (mWrForceAngle) {
      if (!mFeatureD3D11HwAngle->IsEnabled()) {
        mFeatureWrAngle->ForceDisable(FeatureStatus::UnavailableNoAngle,
                                      "ANGLE is disabled",
                                      mFeatureD3D11HwAngle->GetFailureId());
      } else if (!mFeatureGPUProcess->IsEnabled() &&
                 !mWrForceAngleNoGPUProcess) {
        // WebRender with ANGLE relies on the GPU process when on Windows
        mFeatureWrAngle->ForceDisable(
            FeatureStatus::UnavailableNoGpuProcess, "GPU Process is disabled",
            "FEATURE_FAILURE_GPU_PROCESS_DISABLED"_ns);
      }
    } else {
      mFeatureWrAngle->Disable(FeatureStatus::Disabled, "ANGLE is not forced",
                               "FEATURE_FAILURE_ANGLE_NOT_FORCED"_ns);
    }
  } else {
    mFeatureWrAngle->Disable(FeatureStatus::Unavailable, "OS not supported",
                             "FEATURE_FAILURE_OS_NOT_SUPPORTED"_ns);
  }

  if (mWrForceAngle && mFeatureWr->IsEnabled() &&
      !mFeatureWrAngle->IsEnabled()) {
    // Ensure we disable WebRender if ANGLE is unavailable and it is required.
    mFeatureWr->ForceDisable(FeatureStatus::UnavailableNoAngle,
                             "ANGLE is disabled",
                             mFeatureWrAngle->GetFailureId());
  }

  if (!mFeatureWr->IsEnabled() && mDisableHwCompositingNoWr) {
    if (mFeatureHwCompositing->IsEnabled()) {
      // Hardware compositing should be disabled by default if we aren't using
      // WebRender. We had to check if it is enabled at all, because it may
      // already have been forced disabled (e.g. safe mode, headless). It may
      // still be forced on by the user, and if so, this should have no effect.
      mFeatureHwCompositing->Disable(FeatureStatus::Blocked,
                                     "Acceleration blocked by platform", ""_ns);
    }

    if (!mFeatureHwCompositing->IsEnabled() &&
        mFeatureGPUProcess->IsEnabled() && !mGPUProcessAllowSoftware) {
      // We have neither WebRender nor OpenGL, we don't allow the GPU process
      // for basic compositor, and it wasn't disabled already.
      mFeatureGPUProcess->Disable(FeatureStatus::Unavailable,
                                  "Hardware compositing is unavailable.",
                                  ""_ns);
    }
  }

  mFeatureWrDComp->EnableByDefault();
  if (!mWrDCompWinEnabled) {
    mFeatureWrDComp->UserDisable("User disabled via pref",
                                 "FEATURE_FAILURE_DCOMP_PREF_DISABLED"_ns);
  }

  if (!mIsWin10OrLater) {
    // XXX relax win version to windows 8.
    mFeatureWrDComp->Disable(FeatureStatus::Unavailable,
                             "Requires Windows 10 or later",
                             "FEATURE_FAILURE_DCOMP_NOT_WIN10"_ns);
  }

  if (!mFeatureGPUProcess->IsEnabled()) {
    mFeatureWrDComp->Disable(FeatureStatus::Unavailable, "Requires GPU process",
                             "FEATURE_FAILURE_NO_GPU_PROCESS"_ns);
  }

  if (mIsWin10OrLater && !mIsWin11OrLater) {
    // Disable DirectComposition for NVIDIA users on Windows 10 with high/mixed
    // refresh rate monitors due to rendering artifacts. (See bug 1638709.)
    nsAutoString adapterVendorID;
    mGfxInfo->GetAdapterVendorID(adapterVendorID);
    if (adapterVendorID == u"0x10de") {
      bool mixed = false;
      int32_t maxRefreshRate = mGfxInfo->GetMaxRefreshRate(&mixed);
      if (maxRefreshRate > 60 && mixed) {
        mFeatureWrDComp->Disable(FeatureStatus::Blocked,
                                 "Monitor refresh rate too high/mixed",
                                 "NVIDIA_REFRESH_RATE_MIXED"_ns);
      }
    }
  }

  mFeatureWrDComp->MaybeSetFailed(
      mFeatureWr->IsEnabled(), FeatureStatus::Unavailable, "Requires WebRender",
      "FEATURE_FAILURE_DCOMP_NOT_WR"_ns);
  mFeatureWrDComp->MaybeSetFailed(mFeatureWrAngle->IsEnabled(),
                                  FeatureStatus::Unavailable, "Requires ANGLE",
                                  "FEATURE_FAILURE_DCOMP_NOT_ANGLE"_ns);

  if (!mFeatureWrDComp->IsEnabled() && mWrCompositorDCompRequired) {
    mFeatureWrCompositor->ForceDisable(FeatureStatus::Unavailable,
                                       "No DirectComposition usage",
                                       mFeatureWrDComp->GetFailureId());
  }

  // Initialize WebRender partial present config.
  // Partial present is used only when WebRender compositor is not used.
  mFeatureWrPartial->SetDefault(mWrPartialPresent, FeatureStatus::Disabled,
                                "User disabled via pref");
  if (mWrForcePartialPresent) {
    mFeatureWrPartial->UserForceEnable("Force enabled by pref");
  }

  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_PARTIAL_PRESENT,
                         mFeatureWrPartial);

  mFeatureWrShaderCache->SetDefaultFromPref(
      StaticPrefs::GetPrefName_gfx_webrender_program_binary_disk(), true,
      StaticPrefs::GetPrefDefault_gfx_webrender_program_binary_disk(),
      mWrShaderCache);
  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_SHADER_CACHE,
                         mFeatureWrShaderCache);
  if (!mFeatureWr->IsEnabled()) {
    mFeatureWrShaderCache->ForceDisable(FeatureStatus::Unavailable,
                                        "WebRender disabled",
                                        "FEATURE_FAILURE_WR_DISABLED"_ns);
  }

  mFeatureWrOptimizedShaders->EnableByDefault();
  if (!mWrOptimizedShaders) {
    mFeatureWrOptimizedShaders->UserDisable("User disabled via pref",
                                            "FEATURE_FAILURE_PREF_DISABLED"_ns);
  }
  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_OPTIMIZED_SHADERS,
                         mFeatureWrOptimizedShaders);
  if (!mFeatureWr->IsEnabled()) {
    mFeatureWrOptimizedShaders->ForceDisable(FeatureStatus::Unavailable,
                                             "WebRender disabled",
                                             "FEATURE_FAILURE_WR_DISABLED"_ns);
  }

  mFeatureWrScissoredCacheClears->SetDefault(mWrScissoredCacheClearsEnabled,
                                             FeatureStatus::Disabled,
                                             "User disabled via pref");
  if (mWrScissoredCacheClearsForceEnabled) {
    mFeatureWrScissoredCacheClears->UserForceEnable("Force enabled by pref");
  }
  ConfigureFromBlocklist(nsIGfxInfo::FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS,
                         mFeatureWrScissoredCacheClears);
}

}  // namespace gfx
}  // namespace mozilla