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 #include "gfxConfig.h"
7 #include "mozilla/UniquePtr.h"
8 #include "mozilla/Unused.h"
9 #include "mozilla/gfx/GPUParent.h"
10 #include "mozilla/gfx/GraphicsMessages.h"
11 #include "plstr.h"
12 
13 namespace mozilla {
14 namespace gfx {
15 
16 static UniquePtr<gfxConfig> sConfig;
17 
GetFeature(Feature aFeature)18 /* static */ FeatureState& gfxConfig::GetFeature(Feature aFeature) {
19   return sConfig->GetState(aFeature);
20 }
21 
22 /* static */
IsEnabled(Feature aFeature)23 bool gfxConfig::IsEnabled(Feature aFeature) {
24   const FeatureState& state = sConfig->GetState(aFeature);
25   return state.IsEnabled();
26 }
27 
28 /* static */
IsDisabledByDefault(Feature aFeature)29 bool gfxConfig::IsDisabledByDefault(Feature aFeature) {
30   const FeatureState& state = sConfig->GetState(aFeature);
31   return state.DisabledByDefault();
32 }
33 
34 /* static */
IsForcedOnByUser(Feature aFeature)35 bool gfxConfig::IsForcedOnByUser(Feature aFeature) {
36   const FeatureState& state = sConfig->GetState(aFeature);
37   return state.IsForcedOnByUser();
38 }
39 
40 /* static */
GetValue(Feature aFeature)41 FeatureStatus gfxConfig::GetValue(Feature aFeature) {
42   const FeatureState& state = sConfig->GetState(aFeature);
43   return state.GetValue();
44 }
45 
46 /* static */
SetDefault(Feature aFeature,bool aEnable,FeatureStatus aDisableStatus,const char * aDisableMessage)47 bool gfxConfig::SetDefault(Feature aFeature, bool aEnable,
48                            FeatureStatus aDisableStatus,
49                            const char* aDisableMessage) {
50   FeatureState& state = sConfig->GetState(aFeature);
51   return state.SetDefault(aEnable, aDisableStatus, aDisableMessage);
52 }
53 
54 /* static */
DisableByDefault(Feature aFeature,FeatureStatus aDisableStatus,const char * aDisableMessage,const nsACString & aFailureId)55 void gfxConfig::DisableByDefault(Feature aFeature, FeatureStatus aDisableStatus,
56                                  const char* aDisableMessage,
57                                  const nsACString& aFailureId) {
58   FeatureState& state = sConfig->GetState(aFeature);
59   state.DisableByDefault(aDisableStatus, aDisableMessage, aFailureId);
60 }
61 
62 /* static */
EnableByDefault(Feature aFeature)63 void gfxConfig::EnableByDefault(Feature aFeature) {
64   FeatureState& state = sConfig->GetState(aFeature);
65   state.EnableByDefault();
66 }
67 
68 /* static */
SetDefaultFromPref(Feature aFeature,const char * aPrefName,bool aIsEnablePref,bool aDefaultValue)69 void gfxConfig::SetDefaultFromPref(Feature aFeature, const char* aPrefName,
70                                    bool aIsEnablePref, bool aDefaultValue) {
71   FeatureState& state = sConfig->GetState(aFeature);
72   return state.SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue);
73 }
74 
75 /* static */
InitOrUpdate(Feature aFeature,bool aEnable,FeatureStatus aDisableStatus,const char * aDisableMessage)76 bool gfxConfig::InitOrUpdate(Feature aFeature, bool aEnable,
77                              FeatureStatus aDisableStatus,
78                              const char* aDisableMessage) {
79   FeatureState& state = sConfig->GetState(aFeature);
80   return state.InitOrUpdate(aEnable, aDisableStatus, aDisableMessage);
81 }
82 
83 /* static */
SetFailed(Feature aFeature,FeatureStatus aStatus,const char * aMessage,const nsACString & aFailureId)84 void gfxConfig::SetFailed(Feature aFeature, FeatureStatus aStatus,
85                           const char* aMessage, const nsACString& aFailureId) {
86   FeatureState& state = sConfig->GetState(aFeature);
87   state.SetFailed(aStatus, aMessage, aFailureId);
88 }
89 
90 /* static */
Disable(Feature aFeature,FeatureStatus aStatus,const char * aMessage,const nsACString & aFailureId)91 void gfxConfig::Disable(Feature aFeature, FeatureStatus aStatus,
92                         const char* aMessage, const nsACString& aFailureId) {
93   FeatureState& state = sConfig->GetState(aFeature);
94   state.Disable(aStatus, aMessage, aFailureId);
95 }
96 
97 /* static */
UserEnable(Feature aFeature,const char * aMessage)98 void gfxConfig::UserEnable(Feature aFeature, const char* aMessage) {
99   FeatureState& state = sConfig->GetState(aFeature);
100   state.UserEnable(aMessage);
101 }
102 
103 /* static */
UserForceEnable(Feature aFeature,const char * aMessage)104 void gfxConfig::UserForceEnable(Feature aFeature, const char* aMessage) {
105   FeatureState& state = sConfig->GetState(aFeature);
106   state.UserForceEnable(aMessage);
107 }
108 
109 /* static */
UserDisable(Feature aFeature,const char * aMessage,const nsACString & aFailureId)110 void gfxConfig::UserDisable(Feature aFeature, const char* aMessage,
111                             const nsACString& aFailureId) {
112   FeatureState& state = sConfig->GetState(aFeature);
113   state.UserDisable(aMessage, aFailureId);
114 }
115 
116 /* static */
Reenable(Feature aFeature,Fallback aFallback)117 void gfxConfig::Reenable(Feature aFeature, Fallback aFallback) {
118   FeatureState& state = sConfig->GetState(aFeature);
119   MOZ_ASSERT(IsFeatureStatusFailure(state.GetValue()));
120 
121   const char* message = state.GetRuntimeMessage();
122   EnableFallback(aFallback, message);
123   state.SetRuntime(FeatureStatus::Available, nullptr, nsCString());
124 }
125 
126 /* static */
Reset(Feature aFeature)127 void gfxConfig::Reset(Feature aFeature) {
128   FeatureState& state = sConfig->GetState(aFeature);
129   state.Reset();
130 }
131 
132 /* static */
Inherit(Feature aFeature,FeatureStatus aStatus)133 void gfxConfig::Inherit(Feature aFeature, FeatureStatus aStatus) {
134   FeatureState& state = sConfig->GetState(aFeature);
135 
136   state.Reset();
137 
138   switch (aStatus) {
139     case FeatureStatus::Unused:
140       break;
141     case FeatureStatus::Available:
142       gfxConfig::EnableByDefault(aFeature);
143       break;
144     case FeatureStatus::ForceEnabled:
145       gfxConfig::EnableByDefault(aFeature);
146       gfxConfig::UserForceEnable(aFeature, "Inherited from parent process");
147       break;
148     default:
149       gfxConfig::SetDefault(aFeature, false, aStatus,
150                             "Disabled in parent process");
151       break;
152   }
153 }
154 
155 /* static */
Inherit(EnumSet<Feature> aFeatures,const DevicePrefs & aDevicePrefs)156 void gfxConfig::Inherit(EnumSet<Feature> aFeatures,
157                         const DevicePrefs& aDevicePrefs) {
158   for (Feature feature : aFeatures) {
159     FeatureStatus status = FeatureStatus::Unused;
160     switch (feature) {
161       case Feature::HW_COMPOSITING:
162         status = aDevicePrefs.hwCompositing();
163         break;
164       case Feature::D3D11_COMPOSITING:
165         status = aDevicePrefs.d3d11Compositing();
166         break;
167       case Feature::OPENGL_COMPOSITING:
168         status = aDevicePrefs.oglCompositing();
169         break;
170       case Feature::DIRECT2D:
171         status = aDevicePrefs.useD2D1();
172         break;
173       case Feature::WEBGPU:
174         status = aDevicePrefs.webGPU();
175         break;
176       default:
177         break;
178     }
179     gfxConfig::Inherit(feature, status);
180   }
181 }
182 
183 /* static */
UseFallback(Fallback aFallback)184 bool gfxConfig::UseFallback(Fallback aFallback) {
185   return sConfig->UseFallbackImpl(aFallback);
186 }
187 
188 /* static */
EnableFallback(Fallback aFallback,const char * aMessage)189 void gfxConfig::EnableFallback(Fallback aFallback, const char* aMessage) {
190   if (!NS_IsMainThread()) {
191     nsCString message(aMessage);
192     NS_DispatchToMainThread(
193         NS_NewRunnableFunction("gfxConfig::EnableFallback", [=]() -> void {
194           gfxConfig::EnableFallback(aFallback, message.get());
195         }));
196     return;
197   }
198 
199   if (XRE_IsGPUProcess()) {
200     nsCString message(aMessage);
201     Unused << GPUParent::GetSingleton()->SendUsedFallback(aFallback, message);
202     return;
203   }
204 
205   sConfig->EnableFallbackImpl(aFallback, aMessage);
206 }
207 
UseFallbackImpl(Fallback aFallback) const208 bool gfxConfig::UseFallbackImpl(Fallback aFallback) const {
209   return !!(mFallbackBits & (uint64_t(1) << uint64_t(aFallback)));
210 }
211 
EnableFallbackImpl(Fallback aFallback,const char * aMessage)212 void gfxConfig::EnableFallbackImpl(Fallback aFallback, const char* aMessage) {
213   if (!UseFallbackImpl(aFallback)) {
214     MOZ_ASSERT(mNumFallbackLogEntries < kNumFallbacks);
215 
216     FallbackLogEntry& entry = mFallbackLog[mNumFallbackLogEntries];
217     mNumFallbackLogEntries++;
218 
219     entry.mFallback = aFallback;
220     PL_strncpyz(entry.mMessage, aMessage, sizeof(entry.mMessage));
221   }
222   mFallbackBits |= (uint64_t(1) << uint64_t(aFallback));
223 }
224 
225 struct FeatureInfo {
226   const char* name;
227   const char* description;
228 };
229 static const FeatureInfo sFeatureInfo[] = {
230 #define FOR_EACH_FEATURE(name, type, desc) {#name, desc},
231     GFX_FEATURE_MAP(FOR_EACH_FEATURE)
232 #undef FOR_EACH_FEATURE
233         {nullptr, nullptr}};
234 
235 /* static */
ForEachFeature(const FeatureIterCallback & aCallback)236 void gfxConfig::ForEachFeature(const FeatureIterCallback& aCallback) {
237   for (size_t i = 0; i < kNumFeatures; i++) {
238     FeatureState& state = GetFeature(static_cast<Feature>(i));
239     if (!state.IsInitialized()) {
240       continue;
241     }
242 
243     aCallback(sFeatureInfo[i].name, sFeatureInfo[i].description, state);
244   }
245 }
246 
247 static const char* sFallbackNames[] = {
248 #define FOR_EACH_FALLBACK(name) #name,
249     GFX_FALLBACK_MAP(FOR_EACH_FALLBACK)
250 #undef FOR_EACH_FALLBACK
251         nullptr};
252 
253 /* static  */
ForEachFallback(const FallbackIterCallback & aCallback)254 void gfxConfig::ForEachFallback(const FallbackIterCallback& aCallback) {
255   sConfig->ForEachFallbackImpl(aCallback);
256 }
257 
ForEachFallbackImpl(const FallbackIterCallback & aCallback)258 void gfxConfig::ForEachFallbackImpl(const FallbackIterCallback& aCallback) {
259   for (size_t i = 0; i < mNumFallbackLogEntries; i++) {
260     const FallbackLogEntry& entry = mFallbackLog[i];
261     aCallback(sFallbackNames[size_t(entry.mFallback)], entry.mMessage);
262   }
263 }
264 
GetFailureId(Feature aFeature)265 /* static */ const nsCString& gfxConfig::GetFailureId(Feature aFeature) {
266   const FeatureState& state = sConfig->GetState(aFeature);
267   return state.GetFailureId();
268 }
269 
270 /* static */
ImportChange(Feature aFeature,const Maybe<FeatureFailure> & aChange)271 void gfxConfig::ImportChange(Feature aFeature,
272                              const Maybe<FeatureFailure>& aChange) {
273   if (aChange.isNothing()) {
274     return;
275   }
276 
277   const FeatureFailure& failure = aChange.ref();
278   gfxConfig::SetFailed(aFeature, failure.status(), failure.message().get(),
279                        failure.failureId());
280 }
281 
282 /* static */
Init()283 void gfxConfig::Init() { sConfig = mozilla::MakeUnique<gfxConfig>(); }
284 
285 /* static */
Shutdown()286 void gfxConfig::Shutdown() { sConfig = nullptr; }
287 
288 }  // namespace gfx
289 }  // namespace mozilla
290