Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxPlatform.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 * This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "mozilla/FontPropertyTypes.h"
7
#include "mozilla/layers/CompositorManagerChild.h"
8
#include "mozilla/layers/CompositorThread.h"
9
#include "mozilla/layers/ImageBridgeChild.h"
10
#include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
11
#include "mozilla/webrender/RenderThread.h"
12
#include "mozilla/webrender/WebRenderAPI.h"
13
#include "mozilla/webrender/webrender_ffi.h"
14
#include "mozilla/layers/PaintThread.h"
15
#include "mozilla/gfx/gfxVars.h"
16
#include "mozilla/gfx/GPUProcessManager.h"
17
#include "mozilla/gfx/GraphicsMessages.h"
18
#include "mozilla/ClearOnShutdown.h"
19
#include "mozilla/Telemetry.h"
20
#include "mozilla/TimeStamp.h"
21
#include "mozilla/Unused.h"
22
23
#include "mozilla/Logging.h"
24
#include "mozilla/Services.h"
25
#include "nsAppDirectoryServiceDefs.h"
26
27
#include "gfxCrashReporterUtils.h"
28
#include "gfxPlatform.h"
29
#include "gfxPrefs.h"
30
#include "gfxEnv.h"
31
#include "gfxTextRun.h"
32
#include "gfxUserFontSet.h"
33
#include "gfxConfig.h"
34
#include "VRProcessManager.h"
35
#include "VRThread.h"
36
37
#ifdef XP_WIN
38
#include <process.h>
39
#define getpid _getpid
40
#else
41
#include <unistd.h>
42
#endif
43
44
#include "nsXULAppAPI.h"
45
#include "nsDirectoryServiceUtils.h"
46
#include "nsDirectoryServiceDefs.h"
47
48
#if defined(XP_WIN)
49
#include "gfxWindowsPlatform.h"
50
#elif defined(XP_MACOSX)
51
#include "gfxPlatformMac.h"
52
#include "gfxQuartzSurface.h"
53
#include "nsCocoaFeatures.h"
54
#elif defined(MOZ_WIDGET_GTK)
55
#include "gfxPlatformGtk.h"
56
#elif defined(ANDROID)
57
#include "gfxAndroidPlatform.h"
58
#endif
59
60
#ifdef XP_WIN
61
#include <windows.h>
62
#include "mozilla/WindowsVersion.h"
63
#include "mozilla/gfx/DeviceManagerDx.h"
64
#endif
65
66
#include "nsGkAtoms.h"
67
#include "gfxPlatformFontList.h"
68
#include "gfxContext.h"
69
#include "gfxImageSurface.h"
70
#include "nsUnicodeProperties.h"
71
#include "harfbuzz/hb.h"
72
#include "gfxGraphiteShaper.h"
73
#include "gfx2DGlue.h"
74
#include "gfxGradientCache.h"
75
#include "gfxUtils.h" // for NextPowerOfTwo
76
#include "gfxFontMissingGlyphs.h"
77
78
#include "nsExceptionHandler.h"
79
#include "nsUnicodeRange.h"
80
#include "nsServiceManagerUtils.h"
81
#include "nsTArray.h"
82
#include "nsIObserverService.h"
83
#include "nsIScreenManager.h"
84
#include "FrameMetrics.h"
85
#include "MainThreadUtils.h"
86
87
#include "nsWeakReference.h"
88
89
#include "cairo.h"
90
#include "qcms.h"
91
92
#include "imgITools.h"
93
94
#include "plstr.h"
95
#include "nsCRT.h"
96
#include "GLContext.h"
97
#include "GLContextProvider.h"
98
#include "mozilla/gfx/Logging.h"
99
100
#ifdef USE_SKIA
101
# ifdef __GNUC__
102
#  pragma GCC diagnostic push
103
#  pragma GCC diagnostic ignored "-Wshadow"
104
# endif
105
# include "skia/include/core/SkGraphics.h"
106
# ifdef USE_SKIA_GPU
107
#  include "skia/include/gpu/GrContext.h"
108
#  include "skia/include/gpu/gl/GrGLInterface.h"
109
#  include "SkiaGLGlue.h"
110
# endif
111
# ifdef MOZ_ENABLE_FREETYPE
112
#  include "skia/include/ports/SkTypeface_cairo.h"
113
# endif
114
# include "mozilla/gfx/SkMemoryReporter.h"
115
# ifdef __GNUC__
116
#  pragma GCC diagnostic pop // -Wshadow
117
# endif
118
static const uint32_t kDefaultGlyphCacheSize = -1;
119
120
#endif
121
122
#if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
123
class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
124
};
125
#endif
126
127
#include "mozilla/Preferences.h"
128
#include "mozilla/Assertions.h"
129
#include "mozilla/Atomics.h"
130
#include "mozilla/Attributes.h"
131
#include "mozilla/Mutex.h"
132
133
#include "nsAlgorithm.h"
134
#include "nsIGfxInfo.h"
135
#include "nsIXULRuntime.h"
136
#include "VsyncSource.h"
137
#include "SoftwareVsyncSource.h"
138
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
139
#include "mozilla/dom/ContentChild.h"
140
#include "mozilla/dom/TouchEvent.h"
141
#include "gfxVR.h"
142
#include "VRManagerChild.h"
143
#include "mozilla/gfx/GPUParent.h"
144
#include "mozilla/layers/MemoryReportingMLGPU.h"
145
#include "prsystem.h"
146
147
namespace mozilla {
148
namespace layers {
149
void ShutdownTileCache();
150
} // namespace layers
151
} // namespace mozilla
152
153
using namespace mozilla;
154
using namespace mozilla::layers;
155
using namespace mozilla::gl;
156
using namespace mozilla::gfx;
157
158
gfxPlatform *gPlatform = nullptr;
159
static bool gEverInitialized = false;
160
161
const ContentDeviceData* gContentDeviceInitData = nullptr;
162
163
static Mutex* gGfxPlatformPrefsLock = nullptr;
164
165
// These two may point to the same profile
166
static qcms_profile *gCMSOutputProfile = nullptr;
167
static qcms_profile *gCMSsRGBProfile = nullptr;
168
169
static bool gCMSRGBTransformFailed = false;
170
static qcms_transform *gCMSRGBTransform = nullptr;
171
static qcms_transform *gCMSInverseRGBTransform = nullptr;
172
static qcms_transform *gCMSRGBATransform = nullptr;
173
174
static bool gCMSInitialized = false;
175
static eCMSMode gCMSMode = eCMSMode_Off;
176
177
static void ShutdownCMS();
178
179
#include "mozilla/gfx/2D.h"
180
#include "mozilla/gfx/SourceSurfaceCairo.h"
181
using namespace mozilla::gfx;
182
183
/* Class to listen for pref changes so that chrome code can dynamically
184
   force sRGB as an output profile. See Bug #452125. */
185
class SRGBOverrideObserver final : public nsIObserver,
186
                                   public nsSupportsWeakReference
187
{
188
0
    ~SRGBOverrideObserver() = default;
189
public:
190
    NS_DECL_ISUPPORTS
191
    NS_DECL_NSIOBSERVER
192
};
193
194
/// This override of the LogForwarder, initially used for the critical graphics
195
/// errors, is sending the log to the crash annotations as well, but only
196
/// if the capacity set with the method below is >= 2.  We always retain the
197
/// very first critical message, and the latest capacity-1 messages are
198
/// rotated through. Note that we don't expect the total number of times
199
/// this gets called to be large - it is meant for critical errors only.
200
201
class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
202
{
203
public:
204
  explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey);
205
  void Log(const std::string& aString) override;
206
  void CrashAction(LogReason aReason) override;
207
  bool UpdateStringsVector(const std::string& aString) override;
208
209
  LoggingRecord LoggingRecordCopy() override;
210
211
  void SetCircularBufferSize(uint32_t aCapacity);
212
213
private:
214
  // Helper for the Log()
215
  void UpdateCrashReport();
216
217
private:
218
  LoggingRecord mBuffer;
219
  CrashReporter::Annotation mCrashCriticalKey;
220
  uint32_t mMaxCapacity;
221
  int32_t mIndex;
222
  Mutex mMutex;
223
};
224
225
CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey)
226
  : mBuffer()
227
  , mCrashCriticalKey(aKey)
228
  , mMaxCapacity(0)
229
  , mIndex(-1)
230
  , mMutex("CrashStatsLogForwarder")
231
0
{
232
0
}
233
234
void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity)
235
0
{
236
0
  MutexAutoLock lock(mMutex);
237
0
238
0
  mMaxCapacity = aCapacity;
239
0
  mBuffer.reserve(static_cast<size_t>(aCapacity));
240
0
}
241
242
LoggingRecord
243
CrashStatsLogForwarder::LoggingRecordCopy()
244
0
{
245
0
  MutexAutoLock lock(mMutex);
246
0
  return mBuffer;
247
0
}
248
249
bool
250
CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString)
251
0
{
252
0
  // We want at least the first one and the last one.  Otherwise, no point.
253
0
  if (mMaxCapacity < 2) {
254
0
    return false;
255
0
  }
256
0
257
0
  mIndex += 1;
258
0
  MOZ_ASSERT(mIndex >= 0);
259
0
260
0
  // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
261
0
  int32_t index = mIndex ? (mIndex-1) % (mMaxCapacity-1) + 1 : 0;
262
0
  MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
263
0
  MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
264
0
265
0
  double tStamp = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()).ToSecondsSigDigits();
266
0
267
0
  // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
268
0
  // just out of paranoia, but we know index <= mBuffer.size().
269
0
  LoggingRecordEntry newEntry(mIndex,aString,tStamp);
270
0
  if (index >= static_cast<int32_t>(mBuffer.size())) {
271
0
    mBuffer.push_back(newEntry);
272
0
  } else {
273
0
    mBuffer[index] = newEntry;
274
0
  }
275
0
  return true;
276
0
}
277
278
void CrashStatsLogForwarder::UpdateCrashReport()
279
0
{
280
0
  std::stringstream message;
281
0
  std::string logAnnotation;
282
0
283
0
  switch (XRE_GetProcessType()) {
284
0
  case GeckoProcessType_Default:
285
0
    logAnnotation = "|[";
286
0
    break;
287
0
  case GeckoProcessType_Content:
288
0
    logAnnotation = "|[C";
289
0
    break;
290
0
  case GeckoProcessType_GPU:
291
0
    logAnnotation = "|[G";
292
0
    break;
293
0
  default:
294
0
    logAnnotation = "|[X";
295
0
    break;
296
0
  }
297
0
298
0
  for (auto& it : mBuffer) {
299
0
    message << logAnnotation << Get<0>(it) << "]" << Get<1>(it) << " (t=" << Get<2>(it) << ") ";
300
0
  }
301
0
302
0
  nsCString reportString(message.str().c_str());
303
0
  nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey,
304
0
                                                          reportString);
305
0
306
0
  if (annotated != NS_OK) {
307
0
    printf("Crash Annotation %s: %s",
308
0
           CrashReporter::AnnotationToString(mCrashCriticalKey),
309
0
           message.str().c_str());
310
0
  }
311
0
}
312
313
class LogForwarderEvent : public Runnable
314
{
315
0
  ~LogForwarderEvent() override = default;
316
317
public:
318
  NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable)
319
320
  explicit LogForwarderEvent(const nsCString& aMessage)
321
    : mozilla::Runnable("LogForwarderEvent")
322
    , mMessage(aMessage)
323
0
  {
324
0
  }
325
326
0
  NS_IMETHOD Run() override {
327
0
    MOZ_ASSERT(NS_IsMainThread() && (XRE_IsContentProcess() || XRE_IsGPUProcess()));
328
0
329
0
    if (XRE_IsContentProcess()) {
330
0
      dom::ContentChild* cc = dom::ContentChild::GetSingleton();
331
0
      Unused << cc->SendGraphicsError(mMessage);
332
0
    } else if (XRE_IsGPUProcess()) {
333
0
      GPUParent* gp = GPUParent::GetSingleton();
334
0
      Unused << gp->SendGraphicsError(mMessage);
335
0
    }
336
0
337
0
    return NS_OK;
338
0
  }
339
340
protected:
341
  nsCString mMessage;
342
};
343
344
void CrashStatsLogForwarder::Log(const std::string& aString)
345
0
{
346
0
  MutexAutoLock lock(mMutex);
347
0
348
0
  if (UpdateStringsVector(aString)) {
349
0
    UpdateCrashReport();
350
0
  }
351
0
352
0
  // Add it to the parent strings
353
0
  if (!XRE_IsParentProcess()) {
354
0
    nsCString stringToSend(aString.c_str());
355
0
    if (NS_IsMainThread()) {
356
0
      if (XRE_IsContentProcess()) {
357
0
        dom::ContentChild* cc = dom::ContentChild::GetSingleton();
358
0
        Unused << cc->SendGraphicsError(stringToSend);
359
0
      } else if (XRE_IsGPUProcess()) {
360
0
        GPUParent* gp = GPUParent::GetSingleton();
361
0
        Unused << gp->SendGraphicsError(stringToSend);
362
0
      }
363
0
    } else {
364
0
      nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
365
0
      NS_DispatchToMainThread(r1);
366
0
    }
367
0
  }
368
0
}
369
370
class CrashTelemetryEvent : public Runnable
371
{
372
  ~CrashTelemetryEvent() override = default;
373
374
public:
375
  NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable)
376
377
  explicit CrashTelemetryEvent(uint32_t aReason)
378
    : mozilla::Runnable("CrashTelemetryEvent")
379
    , mReason(aReason)
380
0
  {
381
0
  }
382
383
0
  NS_IMETHOD Run() override {
384
0
    MOZ_ASSERT(NS_IsMainThread());
385
0
    Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
386
0
    return NS_OK;
387
0
  }
388
389
protected:
390
  uint32_t mReason;
391
};
392
393
void
394
CrashStatsLogForwarder::CrashAction(LogReason aReason)
395
0
{
396
0
#ifndef RELEASE_OR_BETA
397
0
  // Non-release builds crash by default, but will use telemetry
398
0
  // if this environment variable is present.
399
0
  static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry();
400
#else
401
  // Release builds use telemetry by default, but will crash instead
402
  // if this environment variable is present.
403
  static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash();
404
#endif
405
406
0
  if (useTelemetry) {
407
0
    // The callers need to assure that aReason is in the range
408
0
    // that the telemetry call below supports.
409
0
    if (NS_IsMainThread()) {
410
0
      Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
411
0
    } else {
412
0
      nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
413
0
      NS_DispatchToMainThread(r1);
414
0
    }
415
0
  } else {
416
0
    // ignoring aReason, we can get the information we need from the stack
417
0
    MOZ_CRASH("GFX_CRASH");
418
0
  }
419
0
}
420
421
NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
422
423
0
#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
424
425
0
#define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
426
427
0
#define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
428
429
0
#define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
430
0
#define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
431
432
0
#define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
433
434
0
#define BIDI_NUMERAL_PREF "bidi.numeral"
435
436
0
#define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
437
438
0
#define FONT_VARIATIONS_PREF "layout.css.font-variations.enabled"
439
440
NS_IMETHODIMP
441
SRGBOverrideObserver::Observe(nsISupports *aSubject,
442
                              const char *aTopic,
443
                              const char16_t* someData)
444
0
{
445
0
    NS_ASSERTION(NS_strcmp(someData,
446
0
                           (u"" GFX_PREF_CMS_FORCE_SRGB)) == 0,
447
0
                 "Restarting CMS on wrong pref!");
448
0
    ShutdownCMS();
449
0
    // Update current cms profile.
450
0
    gfxPlatform::CreateCMSOutputProfile();
451
0
    return NS_OK;
452
0
}
453
454
static const char* kObservedPrefs[] = {
455
    "gfx.downloadable_fonts.",
456
    "gfx.font_rendering.",
457
    BIDI_NUMERAL_PREF,
458
    nullptr
459
};
460
461
static void
462
FontPrefChanged(const char* aPref, void* aData)
463
0
{
464
0
    MOZ_ASSERT(aPref);
465
0
    NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
466
0
    gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref);
467
0
}
468
469
void
470
gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy)
471
0
{
472
0
    Factory::PurgeAllCaches();
473
0
    gfxGradientCache::PurgeAllCaches();
474
0
    gfxFontMissingGlyphs::Purge();
475
0
    PurgeSkiaFontCache();
476
0
    PurgeSkiaGPUCache();
477
0
    if (XRE_IsParentProcess()) {
478
0
      layers::CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
479
0
      if (manager) {
480
0
        manager->SendNotifyMemoryPressure();
481
0
      }
482
0
    }
483
0
}
484
485
gfxPlatform::gfxPlatform()
486
  : mHasVariationFontSupport(false)
487
  , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
488
  , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
489
  , mTilesInfoCollector(this, &gfxPlatform::GetTilesSupportInfo)
490
  , mCompositorBackend(layers::LayersBackend::LAYERS_NONE)
491
  , mScreenDepth(0)
492
0
{
493
0
    mAllowDownloadableFonts = UNINITIALIZED_VALUE;
494
0
    mFallbackUsesCmaps = UNINITIALIZED_VALUE;
495
0
496
0
    mWordCacheCharLimit = UNINITIALIZED_VALUE;
497
0
    mWordCacheMaxEntries = UNINITIALIZED_VALUE;
498
0
    mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
499
0
    mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
500
0
    mBidiNumeralOption = UNINITIALIZED_VALUE;
501
0
502
0
    mSkiaGlue = nullptr;
503
0
504
0
    InitBackendPrefs(GetBackendPrefs());
505
0
506
0
    mTotalSystemMemory = PR_GetPhysicalMemorySize();
507
0
508
0
    VRManager::ManagerInit();
509
0
}
510
511
gfxPlatform*
512
gfxPlatform::GetPlatform()
513
0
{
514
0
    if (!gPlatform) {
515
0
        MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(),
516
0
                           "Content Process should have called InitChild() before first GetPlatform()");
517
0
        Init();
518
0
    }
519
0
    return gPlatform;
520
0
}
521
522
bool
523
gfxPlatform::Initialized()
524
0
{
525
0
  return !!gPlatform;
526
0
}
527
528
/* static */ void
529
gfxPlatform::InitChild(const ContentDeviceData& aData)
530
0
{
531
0
  MOZ_ASSERT(XRE_IsContentProcess());
532
0
  MOZ_RELEASE_ASSERT(!gPlatform,
533
0
                     "InitChild() should be called before first GetPlatform()");
534
0
  // Make the provided initial ContentDeviceData available to the init
535
0
  // routines, so they don't have to do a sync request from the parent.
536
0
  gContentDeviceInitData = &aData;
537
0
  Init();
538
0
  gContentDeviceInitData = nullptr;
539
0
}
540
541
void RecordingPrefChanged(const char *aPrefName, void *aClosure)
542
0
{
543
0
  if (Preferences::GetBool("gfx.2d.recording", false)) {
544
0
    nsAutoCString fileName;
545
0
    nsAutoString prefFileName;
546
0
    nsresult rv = Preferences::GetString("gfx.2d.recordingfile", prefFileName);
547
0
    if (NS_SUCCEEDED(rv)) {
548
0
      CopyUTF16toUTF8(prefFileName, fileName);
549
0
    } else {
550
0
      nsCOMPtr<nsIFile> tmpFile;
551
0
      if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
552
0
        return;
553
0
      }
554
0
      fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
555
0
556
0
      nsresult rv = tmpFile->AppendNative(fileName);
557
0
      if (NS_FAILED(rv))
558
0
        return;
559
0
560
#ifdef XP_WIN
561
      rv = tmpFile->GetPath(prefFileName);
562
      CopyUTF16toUTF8(prefFileName, fileName);
563
#else
564
0
      rv = tmpFile->GetNativePath(fileName);
565
0
#endif
566
0
      if (NS_FAILED(rv))
567
0
        return;
568
0
    }
569
0
570
#ifdef XP_WIN
571
    gPlatform->mRecorder = Factory::CreateEventRecorderForFile(prefFileName.BeginReading());
572
#else
573
0
    gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
574
0
#endif
575
0
    printf_stderr("Recording to %s\n", fileName.get());
576
0
    Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
577
0
  } else {
578
0
    Factory::SetGlobalEventRecorder(nullptr);
579
0
  }
580
0
}
581
582
0
#define WR_DEBUG_PREF "gfx.webrender.debug"
583
584
void
585
WebRenderDebugPrefChangeCallback(const char* aPrefName, void*)
586
0
{
587
0
  int32_t flags = 0;
588
0
#define GFX_WEBRENDER_DEBUG(suffix, bit)                          \
589
0
  if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) {        \
590
0
    flags |= (bit);                                             \
591
0
  }
592
0
593
0
  // TODO: It would be nice to get the bit patterns directly from the rust code.
594
0
  GFX_WEBRENDER_DEBUG(".profiler",           1 << 0)
595
0
  GFX_WEBRENDER_DEBUG(".render-targets",     1 << 1)
596
0
  GFX_WEBRENDER_DEBUG(".texture-cache",      1 << 2)
597
0
  GFX_WEBRENDER_DEBUG(".gpu-time-queries",   1 << 3)
598
0
  GFX_WEBRENDER_DEBUG(".gpu-sample-queries", 1 << 4)
599
0
  GFX_WEBRENDER_DEBUG(".disable-batching",   1 << 5)
600
0
  GFX_WEBRENDER_DEBUG(".epochs",             1 << 6)
601
0
  GFX_WEBRENDER_DEBUG(".compact-profiler",   1 << 7)
602
0
  GFX_WEBRENDER_DEBUG(".echo-driver-messages", 1 << 8)
603
0
  GFX_WEBRENDER_DEBUG(".new-frame-indicator", 1 << 9)
604
0
  GFX_WEBRENDER_DEBUG(".new-scene-indicator", 1 << 10)
605
0
  GFX_WEBRENDER_DEBUG(".show-overdraw", 1 << 11)
606
0
#undef GFX_WEBRENDER_DEBUG
607
0
608
0
  gfx::gfxVars::SetWebRenderDebugFlags(flags);
609
0
}
610
611
612
#if defined(USE_SKIA)
613
static uint32_t GetSkiaGlyphCacheSize()
614
0
{
615
0
    // Only increase font cache size on non-android to save memory.
616
0
#if !defined(MOZ_WIDGET_ANDROID)
617
0
    // 10mb as the default pref cache size on desktop due to talos perf tweaking.
618
0
    // Chromium uses 20mb and skia default uses 2mb.
619
0
    // We don't need to change the font cache count since we usually
620
0
    // cache thrash due to asian character sets in talos.
621
0
    // Only increase memory on the content process
622
0
    uint32_t cacheSize = gfxPrefs::SkiaContentFontCacheSize() * 1024 * 1024;
623
0
    if (mozilla::BrowserTabsRemoteAutostart()) {
624
0
      return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
625
0
    }
626
0
627
0
    return cacheSize;
628
#else
629
    return kDefaultGlyphCacheSize;
630
#endif // MOZ_WIDGET_ANDROID
631
}
632
#endif
633
634
class WebRenderMemoryReporter final : public nsIMemoryReporter {
635
public:
636
  NS_DECL_ISUPPORTS
637
  NS_DECL_NSIMEMORYREPORTER
638
639
private:
640
  ~WebRenderMemoryReporter() = default;
641
};
642
643
// Memory reporter for WebRender.
644
//
645
// The reporting within WebRender is manual and incomplete. We could do a much
646
// more thorough job by depending on the malloc_size_of crate, but integrating
647
// that into WebRender is tricky [1].
648
//
649
// So the idea is to start with manual reporting for the large allocations
650
// detected by DMD, and see how much that can cover in practice (which may
651
// require a few rounds of iteration). If that approach turns out to be
652
// fundamentally insufficient, we can either duplicate more of the malloc_size_of
653
// functionality in WebRender, or deal with the complexity of a gecko-only
654
// crate dependency.
655
//
656
// [1] See https://bugzilla.mozilla.org/show_bug.cgi?id=1480293#c1
657
struct WebRenderMemoryReporterHelper {
658
  WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback, nsISupports* aData)
659
    : mCallback(aCallback), mData(aData)
660
0
  {}
661
  nsCOMPtr<nsIHandleReportCallback> mCallback;
662
  nsCOMPtr<nsISupports> mData;
663
664
  void Report(size_t aBytes, const char* aName) const
665
0
  {
666
0
    // Generally, memory reporters pass the empty string as the process name to
667
0
    // indicate "current process". However, if we're using a GPU process, the
668
0
    // measurements will actually take place in that process, and it's easier to
669
0
    // just note that here rather than trying to invoke the memory reporter in
670
0
    // the GPU process.
671
0
    nsAutoCString processName;
672
0
    if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
673
0
      GPUParent::GetGPUProcessName(processName);
674
0
    }
675
0
676
0
    nsPrintfCString path("explicit/gfx/webrender/%s", aName);
677
0
    mCallback->Callback(processName, path,
678
0
                        nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
679
0
                        aBytes, EmptyCString(), mData);
680
0
  }
681
};
682
683
static void
684
FinishAsyncMemoryReport()
685
0
{
686
0
  nsCOMPtr<nsIMemoryReporterManager> imgr =
687
0
    do_GetService("@mozilla.org/memory-reporter-manager;1");
688
0
  if (imgr) {
689
0
    imgr->EndReport();
690
0
  }
691
0
}
692
693
NS_IMPL_ISUPPORTS(WebRenderMemoryReporter, nsIMemoryReporter)
694
695
NS_IMETHODIMP
696
WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
697
                                        nsISupports* aData, bool aAnonymize)
698
0
{
699
0
  MOZ_ASSERT(XRE_IsParentProcess());
700
0
  MOZ_ASSERT(NS_IsMainThread());
701
0
  layers::CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
702
0
  if (!manager) {
703
0
    FinishAsyncMemoryReport();
704
0
    return NS_OK;
705
0
  }
706
0
707
0
  WebRenderMemoryReporterHelper helper(aHandleReport, aData);
708
0
  manager->SendReportMemory(
709
0
    [=](wr::MemoryReport aReport) {
710
0
      helper.Report(aReport.primitive_stores, "primitive-stores");
711
0
      helper.Report(aReport.clip_stores, "clip-stores");
712
0
      helper.Report(aReport.gpu_cache_metadata, "gpu-cache/metadata");
713
0
      helper.Report(aReport.gpu_cache_cpu_mirror, "gpu-cache/cpu-mirror");
714
0
      helper.Report(aReport.render_tasks, "render-tasks");
715
0
      helper.Report(aReport.hit_testers, "hit-testers");
716
0
      helper.Report(aReport.fonts, "resource-cache/font");
717
0
      helper.Report(aReport.images, "resource-cache/images");
718
0
      helper.Report(aReport.rasterized_blobs, "resource-cache/rasterized-blobs");
719
0
      FinishAsyncMemoryReport();
720
0
    },
721
0
    [](mozilla::ipc::ResponseRejectReason aReason) {
722
0
      FinishAsyncMemoryReport();
723
0
    }
724
0
  );
725
0
726
0
  return NS_OK;
727
0
}
728
729
730
void
731
gfxPlatform::Init()
732
0
{
733
0
    MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
734
0
    MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
735
0
736
0
    if (gEverInitialized) {
737
0
        MOZ_CRASH("Already started???");
738
0
    }
739
0
    gEverInitialized = true;
740
0
741
0
    // Initialize the preferences by creating the singleton.
742
0
    gfxPrefs::GetSingleton();
743
0
    gfxVars::Initialize();
744
0
745
0
    gfxConfig::Init();
746
0
747
0
    if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) {
748
0
      GPUProcessManager::Initialize();
749
0
750
0
      if (Preferences::GetBool("media.wmf.skip-blacklist")) {
751
0
        gfxVars::SetPDMWMFDisableD3D11Dlls(nsCString());
752
0
        gfxVars::SetPDMWMFDisableD3D9Dlls(nsCString());
753
0
      } else {
754
0
        nsAutoCString d3d11;
755
0
        Preferences::GetCString("media.wmf.disable-d3d11-for-dlls", d3d11);
756
0
        gfxVars::SetPDMWMFDisableD3D11Dlls(d3d11);
757
0
        nsAutoCString d3d9;
758
0
        Preferences::GetCString("media.wmf.disable-d3d9-for-dlls", d3d9);
759
0
        gfxVars::SetPDMWMFDisableD3D9Dlls(d3d9);
760
0
      }
761
0
762
0
      nsCOMPtr<nsIFile> file;
763
0
      nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
764
0
      if (NS_FAILED(rv)) {
765
0
        gfxVars::SetGREDirectory(nsString());
766
0
      } else {
767
0
        nsAutoString path;
768
0
        file->GetPath(path);
769
0
        gfxVars::SetGREDirectory(nsString(path));
770
0
      }
771
0
    }
772
0
773
0
    // Drop a note in the crash report if we end up forcing an option that could
774
0
    // destabilize things.  New items should be appended at the end (of an existing
775
0
    // or in a new section), so that we don't have to know the version to interpret
776
0
    // these cryptic strings.
777
0
    {
778
0
      nsAutoCString forcedPrefs;
779
0
      // D2D prefs
780
0
      forcedPrefs.AppendPrintf("FP(D%d%d",
781
0
                               gfxPrefs::Direct2DDisabled(),
782
0
                               gfxPrefs::Direct2DForceEnabled());
783
0
      // Layers prefs
784
0
      forcedPrefs.AppendPrintf("-L%d%d%d%d",
785
0
                               gfxPrefs::LayersAMDSwitchableGfxEnabled(),
786
0
                               gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly(),
787
0
                               gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(),
788
0
                               gfxPrefs::LayersD3D11ForceWARP());
789
0
      // WebGL prefs
790
0
      forcedPrefs.AppendPrintf("-W%d%d%d%d%d%d%d%d",
791
0
                               gfxPrefs::WebGLANGLEForceD3D11(),
792
0
                               gfxPrefs::WebGLANGLEForceWARP(),
793
0
                               gfxPrefs::WebGLDisabled(),
794
0
                               gfxPrefs::WebGLDisableANGLE(),
795
0
                               gfxPrefs::WebGLDXGLEnabled(),
796
0
                               gfxPrefs::WebGLForceEnabled(),
797
0
                               gfxPrefs::WebGLForceLayersReadback(),
798
0
                               gfxPrefs::WebGLForceMSAA());
799
0
      // Prefs that don't fit into any of the other sections
800
0
      forcedPrefs.AppendPrintf("-T%d%d%d) ",
801
0
                               gfxPrefs::AndroidRGB16Force(),
802
0
                               gfxPrefs::CanvasAzureAccelerated(),
803
0
                               gfxPrefs::ForceShmemTiles());
804
0
      ScopedGfxFeatureReporter::AppNote(forcedPrefs);
805
0
    }
806
0
807
0
    InitMoz2DLogging();
808
0
809
0
    gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
810
0
811
0
    /* Initialize the GfxInfo service.
812
0
     * Note: we can't call functions on GfxInfo that depend
813
0
     * on gPlatform until after it has been initialized
814
0
     * below. GfxInfo initialization annotates our
815
0
     * crash reports so we want to do it before
816
0
     * we try to load any drivers and do device detection
817
0
     * incase that code crashes. See bug #591561. */
818
0
    nsCOMPtr<nsIGfxInfo> gfxInfo;
819
0
    /* this currently will only succeed on Windows */
820
0
    gfxInfo = services::GetGfxInfo();
821
0
822
#if defined(XP_WIN)
823
    gPlatform = new gfxWindowsPlatform;
824
#elif defined(XP_MACOSX)
825
    gPlatform = new gfxPlatformMac;
826
#elif defined(MOZ_WIDGET_GTK)
827
    gPlatform = new gfxPlatformGtk;
828
#elif defined(ANDROID)
829
    gPlatform = new gfxAndroidPlatform;
830
#else
831
    #error "No gfxPlatform implementation available"
832
#endif
833
    gPlatform->InitAcceleration();
834
0
    gPlatform->InitWebRenderConfig();
835
0
    gPlatform->InitOMTPConfig();
836
0
837
0
    if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
838
0
      GPUProcessManager* gpu = GPUProcessManager::Get();
839
0
      gpu->LaunchGPUProcess();
840
0
    }
841
0
842
0
    if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) {
843
0
      if (gfxPlatform::ForceSoftwareVsync()) {
844
0
        gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource();
845
0
      } else {
846
0
        gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
847
0
      }
848
0
    }
849
0
850
0
#ifdef USE_SKIA
851
0
    SkGraphics::Init();
852
0
#  ifdef MOZ_ENABLE_FREETYPE
853
0
    SkInitCairoFT(gPlatform->FontHintingEnabled());
854
0
#  endif
855
0
#endif
856
0
857
0
    InitLayersIPC();
858
0
859
0
    gPlatform->PopulateScreenInfo();
860
0
    gPlatform->ComputeTileSize();
861
0
862
0
#ifdef MOZ_ENABLE_FREETYPE
863
0
    Factory::SetFTLibrary(gPlatform->GetFTLibrary());
864
0
#endif
865
0
866
0
    gPlatform->mHasVariationFontSupport =
867
0
        gPlatform->CheckVariationFontSupport();
868
0
869
0
    nsresult rv;
870
0
    rv = gfxPlatformFontList::Init();
871
0
    if (NS_FAILED(rv)) {
872
0
        MOZ_CRASH("Could not initialize gfxPlatformFontList");
873
0
    }
874
0
875
0
    gPlatform->mScreenReferenceSurface =
876
0
        gPlatform->CreateOffscreenSurface(IntSize(1, 1),
877
0
                                          SurfaceFormat::A8R8G8B8_UINT32);
878
0
    if (!gPlatform->mScreenReferenceSurface) {
879
0
        MOZ_CRASH("Could not initialize mScreenReferenceSurface");
880
0
    }
881
0
882
0
    gPlatform->mScreenReferenceDrawTarget =
883
0
        gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
884
0
                                                    SurfaceFormat::B8G8R8A8);
885
0
    if (!gPlatform->mScreenReferenceDrawTarget ||
886
0
        !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
887
0
      // If TDR is detected, create a draw target with software backend
888
0
      // and it should be replaced later when the process gets the device
889
0
      // reset notification.
890
0
      if (!gPlatform->DidRenderingDeviceReset()) {
891
0
        gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
892
0
      }
893
0
    }
894
0
895
0
    rv = gfxFontCache::Init();
896
0
    if (NS_FAILED(rv)) {
897
0
        MOZ_CRASH("Could not initialize gfxFontCache");
898
0
    }
899
0
900
0
    /* Create and register our CMS Override observer. */
901
0
    gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
902
0
    Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
903
0
904
0
    Preferences::RegisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
905
0
906
0
    GLContext::PlatformStartup();
907
0
908
0
    Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording");
909
0
910
0
    CreateCMSOutputProfile();
911
0
912
0
    // Listen to memory pressure event so we can purge DrawTarget caches
913
0
    gPlatform->mMemoryPressureObserver = layers::MemoryPressureObserver::Create(gPlatform);
914
0
915
0
    // Request the imgITools service, implicitly initializing ImageLib.
916
0
    nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
917
0
    if (!imgTools) {
918
0
      MOZ_CRASH("Could not initialize ImageLib");
919
0
    }
920
0
921
0
    RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
922
0
    if (XRE_IsParentProcess() && gfxVars::UseWebRender()) {
923
0
      RegisterStrongAsyncMemoryReporter(new WebRenderMemoryReporter());
924
0
    }
925
0
926
0
#ifdef USE_SKIA
927
0
    RegisterStrongMemoryReporter(new SkMemoryReporter());
928
0
#endif
929
0
    mlg::InitializeMemoryReporters();
930
0
931
0
#ifdef USE_SKIA
932
0
    uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
933
0
    if (skiaCacheSize != kDefaultGlyphCacheSize) {
934
0
      SkGraphics::SetFontCacheLimit(skiaCacheSize);
935
0
    }
936
0
#endif
937
0
938
0
    InitNullMetadata();
939
0
    InitOpenGLConfig();
940
0
941
0
    if (XRE_IsParentProcess()) {
942
0
      gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
943
0
      gfxVars::SetDXNV12Blocked(IsDXNV12Blocked());
944
0
      Preferences::Unlock(FONT_VARIATIONS_PREF);
945
0
      if (!gPlatform->HasVariationFontSupport()) {
946
0
        // Ensure variation fonts are disabled and the pref is locked.
947
0
        Preferences::SetBool(FONT_VARIATIONS_PREF, false,
948
0
                             PrefValueKind::Default);
949
0
        Preferences::SetBool(FONT_VARIATIONS_PREF, false);
950
0
        Preferences::Lock(FONT_VARIATIONS_PREF);
951
0
      }
952
0
953
0
      nsCOMPtr<nsIFile> profDir;
954
0
      rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(profDir));
955
0
      if (NS_FAILED(rv)) {
956
0
        gfxVars::SetProfDirectory(nsString());
957
0
      } else {
958
0
        nsAutoString path;
959
0
        profDir->GetPath(path);
960
0
        gfxVars::SetProfDirectory(nsString(path));
961
0
      }
962
0
963
0
      gfxUtils::RemoveShaderCacheFromDiskIfNecessary();
964
0
    }
965
0
966
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
967
0
    if (obs) {
968
0
      obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
969
0
    }
970
0
}
971
972
/* static*/ bool
973
gfxPlatform::IsDXInterop2Blocked()
974
0
{
975
0
  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
976
0
  nsCString blockId;
977
0
  int32_t status;
978
0
  if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_INTEROP2,
979
0
                                              blockId, &status))) {
980
0
    return true;
981
0
  }
982
0
  return status != nsIGfxInfo::FEATURE_STATUS_OK;
983
0
}
984
985
/* static*/ bool
986
gfxPlatform::IsDXNV12Blocked()
987
0
{
988
0
  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
989
0
  nsCString blockId;
990
0
  int32_t status;
991
0
  if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_NV12,
992
0
                                              blockId, &status))) {
993
0
    return true;
994
0
  }
995
0
  return status != nsIGfxInfo::FEATURE_STATUS_OK;
996
0
}
997
998
/* static */ int32_t
999
gfxPlatform::MaxTextureSize()
1000
0
{
1001
0
  // Make sure we don't completely break rendering because of a typo in the
1002
0
  // pref or whatnot.
1003
0
  const int32_t kMinSizePref = 2048;
1004
0
  return std::max(kMinSizePref, gfxPrefs::MaxTextureSizeDoNotUseDirectly());
1005
0
}
1006
1007
/* static */ int32_t
1008
gfxPlatform::MaxAllocSize()
1009
0
{
1010
0
  // Make sure we don't completely break rendering because of a typo in the
1011
0
  // pref or whatnot.
1012
0
  const int32_t kMinAllocPref = 10000000;
1013
0
  return std::max(kMinAllocPref, gfxPrefs::MaxAllocSizeDoNotUseDirectly());
1014
0
}
1015
1016
/* static */ void
1017
gfxPlatform::InitMoz2DLogging()
1018
0
{
1019
0
  auto fwd = new CrashStatsLogForwarder(
1020
0
    CrashReporter::Annotation::GraphicsCriticalError);
1021
0
  fwd->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength());
1022
0
1023
0
  mozilla::gfx::Config cfg;
1024
0
  cfg.mLogForwarder = fwd;
1025
0
  cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize();
1026
0
  cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize();
1027
0
1028
0
  gfx::Factory::Init(cfg);
1029
0
}
1030
1031
/* static */ bool
1032
gfxPlatform::IsHeadless()
1033
3
{
1034
3
    static bool initialized = false;
1035
3
    static bool headless = false;
1036
3
    if (!initialized) {
1037
3
      initialized = true;
1038
3
      headless = PR_GetEnv("MOZ_HEADLESS");
1039
3
    }
1040
3
    return headless;
1041
3
}
1042
1043
static bool sLayersIPCIsUp = false;
1044
1045
/* static */ void
1046
gfxPlatform::InitNullMetadata()
1047
0
{
1048
0
  ScrollMetadata::sNullMetadata = new ScrollMetadata();
1049
0
  ClearOnShutdown(&ScrollMetadata::sNullMetadata);
1050
0
}
1051
1052
void
1053
gfxPlatform::Shutdown()
1054
0
{
1055
0
    // In some cases, gPlatform may not be created but Shutdown() called,
1056
0
    // e.g., during xpcshell tests.
1057
0
    if (!gPlatform) {
1058
0
      return;
1059
0
    }
1060
0
1061
0
    MOZ_ASSERT(!sLayersIPCIsUp);
1062
0
1063
0
    // These may be called before the corresponding subsystems have actually
1064
0
    // started up. That's OK, they can handle it.
1065
0
    gfxFontCache::Shutdown();
1066
0
    gfxGradientCache::Shutdown();
1067
0
    gfxAlphaBoxBlur::ShutdownBlurCache();
1068
0
    gfxGraphiteShaper::Shutdown();
1069
0
    gfxPlatformFontList::Shutdown();
1070
0
    gfxFontMissingGlyphs::Shutdown();
1071
0
    ShutdownTileCache();
1072
0
1073
0
    // Free the various non-null transforms and loaded profiles
1074
0
    ShutdownCMS();
1075
0
1076
0
    /* Unregister our CMS Override callback. */
1077
0
    NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
1078
0
    Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
1079
0
    gPlatform->mSRGBOverrideObserver = nullptr;
1080
0
1081
0
    Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
1082
0
1083
0
    NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
1084
0
    if (gPlatform->mMemoryPressureObserver) {
1085
0
      gPlatform->mMemoryPressureObserver->Unregister();
1086
0
      gPlatform->mMemoryPressureObserver = nullptr;
1087
0
    }
1088
0
    gPlatform->mSkiaGlue = nullptr;
1089
0
1090
0
    if (XRE_IsParentProcess()) {
1091
0
      gPlatform->mVsyncSource->Shutdown();
1092
0
    }
1093
0
1094
0
    gPlatform->mVsyncSource = nullptr;
1095
0
1096
0
    // Shut down the default GL context provider.
1097
0
    GLContextProvider::Shutdown();
1098
0
1099
#if defined(XP_WIN)
1100
    // The above shutdown calls operate on the available context providers on
1101
    // most platforms.  Windows is a "special snowflake", though, and has three
1102
    // context providers available, so we have to shut all of them down.
1103
    // We should only support the default GL provider on Windows; then, this
1104
    // could go away. Unfortunately, we currently support WGL (the default) for
1105
    // WebGL on Optimus.
1106
    GLContextProviderEGL::Shutdown();
1107
#endif
1108
1109
0
    if (XRE_IsParentProcess()) {
1110
0
      GPUProcessManager::Shutdown();
1111
0
      VRProcessManager::Shutdown();
1112
0
    }
1113
0
1114
0
    gfx::Factory::ShutDown();
1115
0
1116
0
    delete gGfxPlatformPrefsLock;
1117
0
1118
0
    gfxVars::Shutdown();
1119
0
    gfxPrefs::DestroySingleton();
1120
0
    gfxFont::DestroySingletons();
1121
0
1122
0
    gfxConfig::Shutdown();
1123
0
1124
0
    gPlatform->WillShutdown();
1125
0
1126
0
    delete gPlatform;
1127
0
    gPlatform = nullptr;
1128
0
}
1129
1130
/* static */ void
1131
gfxPlatform::InitLayersIPC()
1132
0
{
1133
0
  if (sLayersIPCIsUp) {
1134
0
    return;
1135
0
  }
1136
0
  sLayersIPCIsUp = true;
1137
0
1138
0
  if (XRE_IsContentProcess()) {
1139
0
    if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) {
1140
0
      layers::PaintThread::Start();
1141
0
    }
1142
0
  }
1143
0
1144
0
  if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) {
1145
0
    if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && gfxVars::UseWebRender()) {
1146
0
      wr::RenderThread::Start();
1147
0
    }
1148
0
1149
0
    layers::CompositorThreadHolder::Start();
1150
0
    gfx::VRListenerThreadHolder::Start();
1151
0
  }
1152
0
}
1153
1154
/* static */ void
1155
gfxPlatform::ShutdownLayersIPC()
1156
0
{
1157
0
    if (!sLayersIPCIsUp) {
1158
0
      return;
1159
0
    }
1160
0
    sLayersIPCIsUp = false;
1161
0
1162
0
    if (XRE_IsContentProcess()) {
1163
0
        gfx::VRManagerChild::ShutDown();
1164
0
        // cf bug 1215265.
1165
0
        if (gfxPrefs::ChildProcessShutdown()) {
1166
0
          layers::CompositorManagerChild::Shutdown();
1167
0
          layers::ImageBridgeChild::ShutDown();
1168
0
        }
1169
0
1170
0
        if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) {
1171
0
          layers::PaintThread::Shutdown();
1172
0
        }
1173
0
    } else if (XRE_IsParentProcess()) {
1174
0
        gfx::VRManagerChild::ShutDown();
1175
0
        layers::CompositorManagerChild::Shutdown();
1176
0
        layers::ImageBridgeChild::ShutDown();
1177
0
        // This has to happen after shutting down the child protocols.
1178
0
        layers::CompositorThreadHolder::Shutdown();
1179
0
        gfx::VRListenerThreadHolder::Shutdown();
1180
0
        // There is a case that RenderThread exists when gfxVars::UseWebRender() is false.
1181
0
        // This could happen when WebRender was fallbacked to compositor.
1182
0
        if (wr::RenderThread::Get()) {
1183
0
          wr::RenderThread::ShutDown();
1184
0
1185
0
          Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
1186
0
        }
1187
0
1188
0
    } else {
1189
0
      // TODO: There are other kind of processes and we should make sure gfx
1190
0
      // stuff is either not created there or shut down properly.
1191
0
    }
1192
0
}
1193
1194
void
1195
gfxPlatform::WillShutdown()
1196
0
{
1197
0
    // Destoy these first in case they depend on backend-specific resources.
1198
0
    // Otherwise, the backend's destructor would be called before the
1199
0
    // base gfxPlatform destructor.
1200
0
    mScreenReferenceSurface = nullptr;
1201
0
    mScreenReferenceDrawTarget = nullptr;
1202
0
}
1203
1204
gfxPlatform::~gfxPlatform()
1205
0
{
1206
0
    // The cairo folks think we should only clean up in debug builds,
1207
0
    // but we're generally in the habit of trying to shut down as
1208
0
    // cleanly as possible even in production code, so call this
1209
0
    // cairo_debug_* function unconditionally.
1210
0
    //
1211
0
    // because cairo can assert and thus crash on shutdown, don't do this in release builds
1212
#ifdef NS_FREE_PERMANENT_DATA
1213
#ifdef USE_SKIA
1214
    // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
1215
    // Cairo objects e.g. through SkCairoFTTypeface
1216
    SkGraphics::PurgeFontCache();
1217
#endif
1218
1219
#if MOZ_TREE_CAIRO
1220
    cairo_debug_reset_static_data();
1221
#endif
1222
#endif
1223
}
1224
1225
/* static */ already_AddRefed<DrawTarget>
1226
gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
1227
0
{
1228
0
  SurfaceFormat format = aSurface->GetSurfaceFormat();
1229
0
  RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
1230
0
  if (!drawTarget) {
1231
0
    gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in CreateDrawTargetForCairoSurface";
1232
0
    return nullptr;
1233
0
  }
1234
0
  return drawTarget.forget();
1235
0
}
1236
1237
cairo_user_data_key_t kSourceSurface;
1238
1239
/**
1240
 * Record the backend that was used to construct the SourceSurface.
1241
 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
1242
 * we check to make sure the DrawTarget's backend matches the backend
1243
 * for the cached SourceSurface, and only use it if they match. This
1244
 * can avoid expensive and unnecessary readbacks.
1245
 */
1246
struct SourceSurfaceUserData
1247
{
1248
  RefPtr<SourceSurface> mSrcSurface;
1249
  BackendType mBackendType;
1250
};
1251
1252
void SourceBufferDestroy(void *srcSurfUD)
1253
0
{
1254
0
  delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
1255
0
}
1256
1257
UserDataKey kThebesSurface;
1258
1259
struct DependentSourceSurfaceUserData
1260
{
1261
  RefPtr<gfxASurface> mSurface;
1262
};
1263
1264
void SourceSurfaceDestroyed(void *aData)
1265
0
{
1266
0
  delete static_cast<DependentSourceSurfaceUserData*>(aData);
1267
0
}
1268
1269
void
1270
gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
1271
0
{
1272
0
  aSurface->SetData(&kSourceSurface, nullptr, nullptr);
1273
0
}
1274
1275
/* static */ already_AddRefed<SourceSurface>
1276
gfxPlatform::GetSourceSurfaceForSurface(RefPtr<DrawTarget> aTarget,
1277
                                        gfxASurface* aSurface,
1278
                                        bool aIsPlugin)
1279
0
{
1280
0
  if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
1281
0
    return nullptr;
1282
0
  }
1283
0
1284
0
  if (!aTarget) {
1285
0
    aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
1286
0
  }
1287
0
1288
0
  void *userData = aSurface->GetData(&kSourceSurface);
1289
0
1290
0
  if (userData) {
1291
0
    SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
1292
0
1293
0
    if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetBackendType()) {
1294
0
      RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
1295
0
      return srcSurface.forget();
1296
0
    }
1297
0
    // We can just continue here as when setting new user data the destroy
1298
0
    // function will be called for the old user data.
1299
0
  }
1300
0
1301
0
  SurfaceFormat format = aSurface->GetSurfaceFormat();
1302
0
1303
0
  if (aTarget->GetBackendType() == BackendType::CAIRO) {
1304
0
    // If we're going to be used with a CAIRO DrawTarget, then just create a
1305
0
    // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
1306
0
    // DrawTarget and can't pick a better surface type. Doing this also avoids
1307
0
    // readback of aSurface's surface into memory if, for example, aSurface
1308
0
    // wraps an xlib cairo surface (which can be important to avoid a major
1309
0
    // slowdown).
1310
0
    //
1311
0
    // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
1312
0
    // succeeds or not since we don't expect to be able to do any better below
1313
0
    // if it fails.
1314
0
    //
1315
0
    // Note that the returned SourceSurfaceCairo holds a strong reference to
1316
0
    // the cairo_surface_t* that it wraps, which essencially means it holds a
1317
0
    // strong reference to aSurface since aSurface shares its
1318
0
    // cairo_surface_t*'s reference count variable. As a result we can't cache
1319
0
    // srcBuffer on aSurface (see below) since aSurface would then hold a
1320
0
    // strong reference back to srcBuffer, creating a reference loop and a
1321
0
    // memory leak. Not caching is fine since wrapping is cheap enough (no
1322
0
    // copying) so we can just wrap again next time we're called.
1323
0
    return Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1324
0
                                                       aSurface->GetSize(), format);
1325
0
  }
1326
0
1327
0
  RefPtr<SourceSurface> srcBuffer;
1328
0
1329
0
  // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
1330
0
1331
0
  if (!srcBuffer) {
1332
0
    // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
1333
0
    // the same data, then optimize it for aTarget:
1334
0
    RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
1335
0
    if (surf) {
1336
0
      srcBuffer = aIsPlugin ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
1337
0
                            : aTarget->OptimizeSourceSurface(surf);
1338
0
1339
0
      if (srcBuffer == surf) {
1340
0
        // GetWrappedDataSourceSurface returns a SourceSurface that holds a
1341
0
        // strong reference to aSurface since it wraps aSurface's data and
1342
0
        // needs it to stay alive. As a result we can't cache srcBuffer on
1343
0
        // aSurface (below) since aSurface would then hold a strong reference
1344
0
        // back to srcBuffer, creating a reference loop and a memory leak. Not
1345
0
        // caching is fine since wrapping is cheap enough (no copying) so we
1346
0
        // can just wrap again next time we're called.
1347
0
        //
1348
0
        // Note that the check below doesn't catch this since srcBuffer will be a
1349
0
        // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface
1350
0
        // object), which is why we need this separate check.
1351
0
        return srcBuffer.forget();
1352
0
      }
1353
0
    }
1354
0
  }
1355
0
1356
0
  if (!srcBuffer) {
1357
0
    MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
1358
0
               "We already tried CreateSourceSurfaceFromNativeSurface with a "
1359
0
               "DrawTargetCairo above");
1360
0
    // We've run out of performant options. We now try creating a SourceSurface
1361
0
    // using a temporary DrawTargetCairo and then optimizing it to aTarget's
1362
0
    // actual type. The CreateSourceSurfaceFromNativeSurface() call will
1363
0
    // likely create a DataSourceSurface (possibly involving copying and/or
1364
0
    // readback), and the OptimizeSourceSurface may well copy again and upload
1365
0
    // to the GPU. So, while this code path is rarely hit, hitting it may be
1366
0
    // very slow.
1367
0
    srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1368
0
                                                            aSurface->GetSize(), format);
1369
0
    if (srcBuffer) {
1370
0
      srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
1371
0
    }
1372
0
  }
1373
0
1374
0
  if (!srcBuffer) {
1375
0
    return nullptr;
1376
0
  }
1377
0
1378
0
  if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
1379
0
       static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1380
0
         aSurface->CairoSurface()) ||
1381
0
      (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
1382
0
       static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1383
0
         aSurface->CairoSurface())) {
1384
0
    // See the "Note that the returned SourceSurfaceCairo..." comment above.
1385
0
    return srcBuffer.forget();
1386
0
  }
1387
0
1388
0
  // Add user data to aSurface so we can cache lookups in the future.
1389
0
  auto *srcSurfUD = new SourceSurfaceUserData;
1390
0
  srcSurfUD->mBackendType = aTarget->GetBackendType();
1391
0
  srcSurfUD->mSrcSurface = srcBuffer;
1392
0
  aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
1393
0
1394
0
  return srcBuffer.forget();
1395
0
}
1396
1397
already_AddRefed<DataSourceSurface>
1398
gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
1399
0
{
1400
0
  RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
1401
0
  if (!image) {
1402
0
    return nullptr;
1403
0
  }
1404
0
  RefPtr<DataSourceSurface> result =
1405
0
    Factory::CreateWrappingDataSourceSurface(image->Data(),
1406
0
                                             image->Stride(),
1407
0
                                             image->GetSize(),
1408
0
                                             ImageFormatToSurfaceFormat(image->Format()));
1409
0
1410
0
  if (!result) {
1411
0
    return nullptr;
1412
0
  }
1413
0
1414
0
  // If we wrapped the underlying data of aSurface, then we need to add user data
1415
0
  // to make sure aSurface stays alive until we are done with the data.
1416
0
  auto *srcSurfUD = new DependentSourceSurfaceUserData;
1417
0
  srcSurfUD->mSurface = aSurface;
1418
0
  result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
1419
0
1420
0
  return result.forget();
1421
0
}
1422
1423
void
1424
gfxPlatform::ComputeTileSize()
1425
0
{
1426
0
  // The tile size should be picked in the parent processes
1427
0
  // and sent to the child processes over IPDL GetTileSize.
1428
0
  if (!XRE_IsParentProcess()) {
1429
0
    return;
1430
0
  }
1431
0
1432
0
  int32_t w = gfxPrefs::LayersTileWidth();
1433
0
  int32_t h = gfxPrefs::LayersTileHeight();
1434
0
1435
0
  if (gfxPrefs::LayersTilesAdjust()) {
1436
0
    gfx::IntSize screenSize = GetScreenSize();
1437
0
    if (screenSize.width > 0) {
1438
0
      // Choose a size so that there are between 2 and 4 tiles per screen width.
1439
0
      // FIXME: we should probably make sure this is within the max texture size,
1440
0
      // but I think everything should at least support 1024
1441
0
      w = h = clamped(int32_t(RoundUpPow2(screenSize.width)) / 4, 256, 1024);
1442
0
    }
1443
0
  }
1444
0
1445
0
  // Don't allow changing the tile size after we've set it.
1446
0
  // Right now the code assumes that the tile size doesn't change.
1447
0
  MOZ_ASSERT(gfxVars::TileSize().width == -1 &&
1448
0
             gfxVars::TileSize().height == -1);
1449
0
1450
0
  gfxVars::SetTileSize(IntSize(w, h));
1451
0
}
1452
1453
void
1454
gfxPlatform::PopulateScreenInfo()
1455
0
{
1456
0
  nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1");
1457
0
  MOZ_ASSERT(manager, "failed to get nsIScreenManager");
1458
0
1459
0
  nsCOMPtr<nsIScreen> screen;
1460
0
  manager->GetPrimaryScreen(getter_AddRefs(screen));
1461
0
  if (!screen) {
1462
0
    // This can happen in xpcshell, for instance
1463
0
    return;
1464
0
  }
1465
0
1466
0
  screen->GetColorDepth(&mScreenDepth);
1467
0
  if (XRE_IsParentProcess()) {
1468
0
    gfxVars::SetScreenDepth(mScreenDepth);
1469
0
  }
1470
0
1471
0
  int left, top;
1472
0
  screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
1473
0
}
1474
1475
bool
1476
gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
1477
0
{
1478
0
  if (!aTarget || !aTarget->IsValid()) {
1479
0
    return false;
1480
0
  }
1481
0
1482
0
#ifdef USE_SKIA_GPU
1483
0
 // Skia content rendering doesn't support GPU acceleration, so we can't
1484
0
 // use the same backend if the current backend is accelerated.
1485
0
 if ((aTarget->GetType() == DrawTargetType::HARDWARE_RASTER)
1486
0
     && (aTarget->GetBackendType() ==  BackendType::SKIA))
1487
0
 {
1488
0
  return false;
1489
0
 }
1490
0
#endif
1491
0
1492
0
  return SupportsAzureContentForType(aTarget->GetBackendType());
1493
0
}
1494
1495
bool gfxPlatform::AllowOpenGLCanvas()
1496
0
{
1497
0
  // For now, only allow Skia+OpenGL, unless it's blocked.
1498
0
  // Allow acceleration on Skia if the preference is set, unless it's blocked
1499
0
  // as long as we have the accelerated layers
1500
0
1501
0
  // The compositor backend is only set correctly in the parent process,
1502
0
  // so we let content process always assume correct compositor backend.
1503
0
  // The callers have to do the right thing.
1504
0
  bool correctBackend = !XRE_IsParentProcess() ||
1505
0
    ((mCompositorBackend == LayersBackend::LAYERS_OPENGL ||
1506
0
      mCompositorBackend == LayersBackend::LAYERS_WR) &&
1507
0
     (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
1508
0
1509
0
  if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
1510
0
    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
1511
0
    int32_t status;
1512
0
    nsCString discardFailureId;
1513
0
    return !gfxInfo ||
1514
0
      (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
1515
0
                                              discardFailureId,
1516
0
                                              &status)) &&
1517
0
       status == nsIGfxInfo::FEATURE_STATUS_OK);
1518
0
  }
1519
0
  return false;
1520
0
}
1521
1522
void
1523
gfxPlatform::InitializeSkiaCacheLimits()
1524
0
{
1525
0
  if (AllowOpenGLCanvas()) {
1526
0
#ifdef USE_SKIA_GPU
1527
0
    bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
1528
0
    int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
1529
0
    uint64_t cacheSizeLimit = std::max(gfxPrefs::CanvasSkiaGLCacheSize(), (int32_t)0);
1530
0
1531
0
    // Prefs are in megabytes, but we want the sizes in bytes
1532
0
    cacheSizeLimit *= 1024*1024;
1533
0
1534
0
    if (usingDynamicCache) {
1535
0
      if (mTotalSystemMemory < 512*1024*1024) {
1536
0
        // We need a very minimal cache on anything smaller than 512mb.
1537
0
        // Note the large jump as we cross 512mb (from 2mb to 32mb).
1538
0
        cacheSizeLimit = 2*1024*1024;
1539
0
      } else if (mTotalSystemMemory > 0) {
1540
0
        cacheSizeLimit = mTotalSystemMemory / 16;
1541
0
      }
1542
0
    }
1543
0
1544
0
    // Ensure cache size doesn't overflow on 32-bit platforms.
1545
0
    cacheSizeLimit = std::min(cacheSizeLimit, (uint64_t)SIZE_MAX);
1546
0
1547
  #ifdef DEBUG
1548
    printf_stderr("Determined SkiaGL cache limits: Size %" PRIu64 ", Items: %i\n", cacheSizeLimit, cacheItemLimit);
1549
  #endif
1550
1551
0
    mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, (size_t)cacheSizeLimit);
1552
0
#endif
1553
0
  }
1554
0
}
1555
1556
SkiaGLGlue*
1557
gfxPlatform::GetSkiaGLGlue()
1558
0
{
1559
0
#ifdef USE_SKIA_GPU
1560
0
  // Check the accelerated Canvas is enabled for the first time,
1561
0
  // because the callers should check it before using.
1562
0
  if (!mSkiaGlue && !AllowOpenGLCanvas()) {
1563
0
    return nullptr;
1564
0
  }
1565
0
1566
0
  if (!mSkiaGlue) {
1567
0
    /* Dummy context. We always draw into a FBO.
1568
0
     *
1569
0
     * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
1570
0
     * stands, this only works on the main thread.
1571
0
     */
1572
0
    RefPtr<GLContext> glContext;
1573
0
    nsCString discardFailureId;
1574
0
    glContext = GLContextProvider::CreateHeadless(CreateContextFlags::REQUIRE_COMPAT_PROFILE |
1575
0
                                                  CreateContextFlags::ALLOW_OFFLINE_RENDERER,
1576
0
                                                  &discardFailureId);
1577
0
    if (!glContext) {
1578
0
      printf_stderr("Failed to create GLContext for SkiaGL!\n");
1579
0
      return nullptr;
1580
0
    }
1581
0
    mSkiaGlue = new SkiaGLGlue(glContext);
1582
0
    MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
1583
0
    InitializeSkiaCacheLimits();
1584
0
  }
1585
0
#endif
1586
0
1587
0
  return mSkiaGlue;
1588
0
}
1589
1590
void
1591
gfxPlatform::PurgeSkiaFontCache()
1592
0
{
1593
0
#ifdef USE_SKIA
1594
0
  if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() == BackendType::SKIA) {
1595
0
    SkGraphics::PurgeFontCache();
1596
0
  }
1597
0
#endif
1598
0
}
1599
1600
void
1601
gfxPlatform::PurgeSkiaGPUCache()
1602
0
{
1603
0
#ifdef USE_SKIA_GPU
1604
0
  if (!mSkiaGlue)
1605
0
      return;
1606
0
1607
0
  mSkiaGlue->GetGrContext()->freeGpuResources();
1608
0
  // GrContext::flush() doesn't call glFlush. Call it here.
1609
0
  mSkiaGlue->GetGLContext()->MakeCurrent();
1610
0
  mSkiaGlue->GetGLContext()->fFlush();
1611
0
#endif
1612
0
}
1613
1614
bool
1615
gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL()
1616
0
{
1617
0
  return true;
1618
0
}
1619
1620
already_AddRefed<DrawTarget>
1621
gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
1622
0
{
1623
0
  // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
1624
0
  // create the best offscreen surface for the current system and situation. We
1625
0
  // can easily take advantage of this for the Cairo backend, so that's what we
1626
0
  // do.
1627
0
  // mozilla::gfx::Factory can get away without having all this knowledge for
1628
0
  // now, but this might need to change in the future (using
1629
0
  // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
1630
0
  // backends).
1631
0
  if (aBackend == BackendType::CAIRO) {
1632
0
    RefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
1633
0
    if (!surf || surf->CairoStatus()) {
1634
0
      return nullptr;
1635
0
    }
1636
0
    return CreateDrawTargetForSurface(surf, aSize);
1637
0
  }
1638
0
  return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
1639
0
}
1640
1641
already_AddRefed<DrawTarget>
1642
gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
1643
0
{
1644
0
  NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1645
0
  RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
1646
0
  if (target ||
1647
0
      mFallbackCanvasBackend == BackendType::NONE) {
1648
0
    return target.forget();
1649
0
  }
1650
0
1651
#ifdef XP_WIN
1652
  // On Windows, the fallback backend (Cairo) should use its image backend.
1653
  return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
1654
#else
1655
0
  return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
1656
0
#endif
1657
0
}
1658
1659
already_AddRefed<DrawTarget>
1660
gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize,
1661
                                              SurfaceFormat aFormat,
1662
                                              bool aFallback)
1663
0
{
1664
0
  BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
1665
0
  NS_ASSERTION(backend != BackendType::NONE, "No backend.");
1666
0
  return CreateDrawTargetForBackend(backend, aSize, aFormat);
1667
0
}
1668
1669
already_AddRefed<DrawTarget>
1670
gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
1671
                                             const IntSize& aSize,
1672
                                             SurfaceFormat aFormat)
1673
0
{
1674
0
  RefPtr<DrawTarget> dt;
1675
0
1676
0
  if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
1677
0
    dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
1678
0
  } else {
1679
0
#ifdef USE_SKIA
1680
0
    BackendType backendType = BackendType::SKIA;
1681
#else
1682
    BackendType backendType = BackendType::CAIRO;
1683
#endif
1684
    dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
1685
0
  }
1686
0
1687
0
  return dt.forget();
1688
0
}
1689
1690
/* static */ already_AddRefed<DrawTarget>
1691
gfxPlatform::CreateDrawTargetForData(unsigned char* aData,
1692
                                     const IntSize& aSize,
1693
                                     int32_t aStride,
1694
                                     SurfaceFormat aFormat,
1695
                                     bool aUninitialized)
1696
0
{
1697
0
  BackendType backendType = gfxVars::ContentBackend();
1698
0
  NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
1699
0
1700
0
  if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
1701
0
#ifdef USE_SKIA
1702
0
    backendType = BackendType::SKIA;
1703
#else
1704
    backendType = BackendType::CAIRO;
1705
#endif
1706
  }
1707
0
1708
0
  RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
1709
0
                                                           aData, aSize,
1710
0
                                                           aStride, aFormat,
1711
0
                                                           aUninitialized);
1712
0
1713
0
  return dt.forget();
1714
0
}
1715
1716
/* static */ BackendType
1717
gfxPlatform::BackendTypeForName(const nsCString& aName)
1718
0
{
1719
0
  if (aName.EqualsLiteral("cairo"))
1720
0
    return BackendType::CAIRO;
1721
0
  if (aName.EqualsLiteral("skia"))
1722
0
    return BackendType::SKIA;
1723
0
  if (aName.EqualsLiteral("direct2d"))
1724
0
    return BackendType::DIRECT2D;
1725
0
  if (aName.EqualsLiteral("direct2d1.1"))
1726
0
    return BackendType::DIRECT2D1_1;
1727
0
  return BackendType::NONE;
1728
0
}
1729
1730
nsresult
1731
gfxPlatform::GetFontList(nsAtom *aLangGroup,
1732
                         const nsACString& aGenericFamily,
1733
                         nsTArray<nsString>& aListOfFonts)
1734
0
{
1735
0
    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
1736
0
                                                         aGenericFamily,
1737
0
                                                         aListOfFonts);
1738
0
    return NS_OK;
1739
0
}
1740
1741
nsresult
1742
gfxPlatform::UpdateFontList()
1743
0
{
1744
0
    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
1745
0
    return NS_OK;
1746
0
}
1747
1748
void
1749
gfxPlatform::GetStandardFamilyName(const nsCString& aFontName,
1750
                                   nsACString& aFamilyName)
1751
0
{
1752
0
    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
1753
0
                                                                   aFamilyName);
1754
0
}
1755
1756
nsAutoCString
1757
gfxPlatform::GetDefaultFontName(const nsACString& aLangGroup,
1758
                                const nsACString& aGenericFamily)
1759
0
{
1760
0
    // To benefit from Return Value Optimization, all paths here must return
1761
0
    // this one variable:
1762
0
    nsAutoCString result;
1763
0
1764
0
    gfxFontFamily* fontFamily = gfxPlatformFontList::PlatformFontList()->
1765
0
        GetDefaultFontFamily(aLangGroup, aGenericFamily);
1766
0
    if (fontFamily) {
1767
0
      fontFamily->LocalizedName(result);
1768
0
    } // (else, leave 'result' empty)
1769
0
1770
0
    return result;
1771
0
}
1772
1773
bool
1774
gfxPlatform::DownloadableFontsEnabled()
1775
0
{
1776
0
    if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1777
0
        mAllowDownloadableFonts =
1778
0
            Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1779
0
    }
1780
0
1781
0
    return mAllowDownloadableFonts;
1782
0
}
1783
1784
bool
1785
gfxPlatform::UseCmapsDuringSystemFallback()
1786
0
{
1787
0
    if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1788
0
        mFallbackUsesCmaps =
1789
0
            Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1790
0
    }
1791
0
1792
0
    return mFallbackUsesCmaps;
1793
0
}
1794
1795
bool
1796
gfxPlatform::OpenTypeSVGEnabled()
1797
0
{
1798
0
    if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1799
0
        mOpenTypeSVGEnabled =
1800
0
            Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1801
0
    }
1802
0
1803
0
    return mOpenTypeSVGEnabled > 0;
1804
0
}
1805
1806
uint32_t
1807
gfxPlatform::WordCacheCharLimit()
1808
0
{
1809
0
    if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1810
0
        mWordCacheCharLimit =
1811
0
            Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1812
0
        if (mWordCacheCharLimit < 0) {
1813
0
            mWordCacheCharLimit = 32;
1814
0
        }
1815
0
    }
1816
0
1817
0
    return uint32_t(mWordCacheCharLimit);
1818
0
}
1819
1820
uint32_t
1821
gfxPlatform::WordCacheMaxEntries()
1822
0
{
1823
0
    if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1824
0
        mWordCacheMaxEntries =
1825
0
            Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1826
0
        if (mWordCacheMaxEntries < 0) {
1827
0
            mWordCacheMaxEntries = 10000;
1828
0
        }
1829
0
    }
1830
0
1831
0
    return uint32_t(mWordCacheMaxEntries);
1832
0
}
1833
1834
bool
1835
gfxPlatform::UseGraphiteShaping()
1836
0
{
1837
0
    if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1838
0
        mGraphiteShapingEnabled =
1839
0
            Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1840
0
    }
1841
0
1842
0
    return mGraphiteShapingEnabled;
1843
0
}
1844
1845
bool
1846
gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags)
1847
0
{
1848
0
    // check for strange format flags
1849
0
    MOZ_ASSERT(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
1850
0
               "strange font format hint set");
1851
0
1852
0
    // accept "common" formats that we support on all platforms
1853
0
    if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
1854
0
        return true;
1855
0
    }
1856
0
1857
0
    // reject all other formats, known and unknown
1858
0
    if (aFormatFlags != 0) {
1859
0
        return false;
1860
0
    }
1861
0
1862
0
    // no format hint set, need to look at data
1863
0
    return true;
1864
0
}
1865
1866
gfxFontEntry*
1867
gfxPlatform::LookupLocalFont(const nsACString& aFontName,
1868
                             WeightRange aWeightForEntry,
1869
                             StretchRange aStretchForEntry,
1870
                             SlantStyleRange aStyleForEntry)
1871
0
{
1872
0
    return gfxPlatformFontList::PlatformFontList()->
1873
0
        LookupLocalFont(aFontName, aWeightForEntry, aStretchForEntry,
1874
0
                        aStyleForEntry);
1875
0
}
1876
1877
gfxFontEntry*
1878
gfxPlatform::MakePlatformFont(const nsACString& aFontName,
1879
                              WeightRange aWeightForEntry,
1880
                              StretchRange aStretchForEntry,
1881
                              SlantStyleRange aStyleForEntry,
1882
                              const uint8_t* aFontData,
1883
                              uint32_t aLength)
1884
0
{
1885
0
    return gfxPlatformFontList::PlatformFontList()->
1886
0
        MakePlatformFont(aFontName, aWeightForEntry, aStretchForEntry,
1887
0
                         aStyleForEntry, aFontData, aLength);
1888
0
}
1889
1890
mozilla::layers::DiagnosticTypes
1891
gfxPlatform::GetLayerDiagnosticTypes()
1892
0
{
1893
0
  mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
1894
0
  if (gfxPrefs::DrawLayerBorders()) {
1895
0
    type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
1896
0
  }
1897
0
  if (gfxPrefs::DrawTileBorders()) {
1898
0
    type |= mozilla::layers::DiagnosticTypes::TILE_BORDERS;
1899
0
  }
1900
0
  if (gfxPrefs::DrawBigImageBorders()) {
1901
0
    type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS;
1902
0
  }
1903
0
  if (gfxPrefs::FlashLayerBorders()) {
1904
0
    type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
1905
0
  }
1906
0
  return type;
1907
0
}
1908
1909
BackendPrefsData
1910
gfxPlatform::GetBackendPrefs() const
1911
0
{
1912
0
  BackendPrefsData data;
1913
0
1914
0
  data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO);
1915
0
  data.mContentBitmask = BackendTypeBit(BackendType::CAIRO);
1916
0
#ifdef USE_SKIA
1917
0
  data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA);
1918
0
  data.mContentBitmask |= BackendTypeBit(BackendType::SKIA);
1919
0
#endif
1920
0
  data.mCanvasDefault = BackendType::CAIRO;
1921
0
  data.mContentDefault = BackendType::CAIRO;
1922
0
1923
0
  return data;
1924
0
}
1925
1926
void
1927
gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData)
1928
0
{
1929
0
    mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
1930
0
    if (mPreferredCanvasBackend == BackendType::NONE) {
1931
0
        mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
1932
0
    }
1933
0
1934
0
    if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
1935
0
      // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
1936
0
      // fails it means the surface was too big or there's something wrong with
1937
0
      // the device. D2D 1.0 will encounter a similar situation.
1938
0
      mFallbackCanvasBackend =
1939
0
          GetCanvasBackendPref(aPrefsData.mCanvasBitmask &
1940
0
                               ~(BackendTypeBit(mPreferredCanvasBackend) | BackendTypeBit(BackendType::DIRECT2D)));
1941
0
    } else {
1942
0
      mFallbackCanvasBackend =
1943
0
          GetCanvasBackendPref(aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1944
0
    }
1945
0
1946
0
1947
0
    mContentBackendBitmask = aPrefsData.mContentBitmask;
1948
0
    mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1949
0
    if (mContentBackend == BackendType::NONE) {
1950
0
        mContentBackend = aPrefsData.mContentDefault;
1951
0
        // mContentBackendBitmask is our canonical reference for supported
1952
0
        // backends so we need to add the default if we are using it and
1953
0
        // overriding the prefs.
1954
0
        mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
1955
0
    }
1956
0
1957
0
    uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA) |
1958
0
                             BackendTypeBit(BackendType::CAIRO);
1959
0
    mSoftwareBackend = GetContentBackendPref(swBackendBits);
1960
0
1961
0
    if (XRE_IsParentProcess()) {
1962
0
        gfxVars::SetContentBackend(mContentBackend);
1963
0
        gfxVars::SetSoftwareBackend(mSoftwareBackend);
1964
0
    }
1965
0
}
1966
1967
/* static */ BackendType
1968
gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1969
0
{
1970
0
    return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1971
0
}
1972
1973
/* static */ BackendType
1974
gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1975
0
{
1976
0
    return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1977
0
}
1978
1979
/* static */ BackendType
1980
gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
1981
0
{
1982
0
    nsTArray<nsCString> backendList;
1983
0
    nsAutoCString prefString;
1984
0
    if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) {
1985
0
        ParseString(prefString, ',', backendList);
1986
0
    }
1987
0
1988
0
    uint32_t allowedBackends = 0;
1989
0
    BackendType result = BackendType::NONE;
1990
0
    for (uint32_t i = 0; i < backendList.Length(); ++i) {
1991
0
        BackendType type = BackendTypeForName(backendList[i]);
1992
0
        if (BackendTypeBit(type) & aBackendBitmask) {
1993
0
            allowedBackends |= BackendTypeBit(type);
1994
0
            if (result == BackendType::NONE) {
1995
0
                result = type;
1996
0
            }
1997
0
        }
1998
0
    }
1999
0
2000
0
    aBackendBitmask = allowedBackends;
2001
0
    return result;
2002
0
}
2003
2004
bool
2005
gfxPlatform::InSafeMode()
2006
0
{
2007
0
  static bool sSafeModeInitialized = false;
2008
0
  static bool sInSafeMode = false;
2009
0
2010
0
  if (!sSafeModeInitialized) {
2011
0
    sSafeModeInitialized = true;
2012
0
    nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
2013
0
    if (xr) {
2014
0
      xr->GetInSafeMode(&sInSafeMode);
2015
0
    }
2016
0
  }
2017
0
  return sInSafeMode;
2018
0
}
2019
2020
bool
2021
gfxPlatform::OffMainThreadCompositingEnabled()
2022
0
{
2023
0
  return UsesOffMainThreadCompositing();
2024
0
}
2025
2026
eCMSMode
2027
gfxPlatform::GetCMSMode()
2028
0
{
2029
0
    if (!gCMSInitialized) {
2030
0
        int32_t mode = gfxPrefs::CMSMode();
2031
0
        if (mode >= 0 && mode < eCMSMode_AllCount) {
2032
0
            gCMSMode = static_cast<eCMSMode>(mode);
2033
0
        }
2034
0
2035
0
        bool enableV4 = gfxPrefs::CMSEnableV4();
2036
0
        if (enableV4) {
2037
0
            qcms_enable_iccv4();
2038
0
        }
2039
0
        gCMSInitialized = true;
2040
0
    }
2041
0
    return gCMSMode;
2042
0
}
2043
2044
int
2045
gfxPlatform::GetRenderingIntent()
2046
0
{
2047
0
  // gfxPrefs.h is using 0 as the default for the rendering
2048
0
  // intent preference, based on that being the value for
2049
0
  // QCMS_INTENT_DEFAULT.  Assert here to catch if that ever
2050
0
  // changes and we can then figure out what to do about it.
2051
0
  MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
2052
0
2053
0
  /* Try to query the pref system for a rendering intent. */
2054
0
  int32_t pIntent = gfxPrefs::CMSRenderingIntent();
2055
0
  if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
2056
0
    /* If the pref is out of range, use embedded profile. */
2057
0
    pIntent = -1;
2058
0
  }
2059
0
  return pIntent;
2060
0
}
2061
2062
void
2063
gfxPlatform::TransformPixel(const Color& in, Color& out, qcms_transform *transform)
2064
0
{
2065
0
2066
0
    if (transform) {
2067
0
        /* we want the bytes in RGB order */
2068
0
#ifdef IS_LITTLE_ENDIAN
2069
0
        /* ABGR puts the bytes in |RGBA| order on little endian */
2070
0
        uint32_t packed = in.ToABGR();
2071
0
        qcms_transform_data(transform,
2072
0
                       (uint8_t *)&packed, (uint8_t *)&packed,
2073
0
                       1);
2074
0
        out = Color::FromABGR(packed);
2075
#else
2076
        /* ARGB puts the bytes in |ARGB| order on big endian */
2077
        uint32_t packed = in.UnusualToARGB();
2078
        /* add one to move past the alpha byte */
2079
        qcms_transform_data(transform,
2080
                       (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
2081
                       1);
2082
        out = Color::UnusualFromARGB(packed);
2083
#endif
2084
    }
2085
0
2086
0
    else if (&out != &in)
2087
0
        out = in;
2088
0
}
2089
2090
void
2091
gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
2092
0
{
2093
0
    mem = nullptr;
2094
0
    size = 0;
2095
0
}
2096
2097
void
2098
gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
2099
0
{
2100
0
    nsAutoCString fname;
2101
0
    Preferences::GetCString("gfx.color_management.display_profile", fname);
2102
0
    if (!fname.IsEmpty()) {
2103
0
        qcms_data_from_path(fname.get(), &mem, &size);
2104
0
    }
2105
0
    else {
2106
0
        gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
2107
0
    }
2108
0
}
2109
2110
void
2111
gfxPlatform::CreateCMSOutputProfile()
2112
0
{
2113
0
    if (!gCMSOutputProfile) {
2114
0
        /* Determine if we're using the internal override to force sRGB as
2115
0
           an output profile for reftests. See Bug 452125.
2116
0
2117
0
           Note that we don't normally (outside of tests) set a
2118
0
           default value of this preference, which means nsIPrefBranch::GetBoolPref
2119
0
           will typically throw (and leave its out-param untouched).
2120
0
         */
2121
0
        if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
2122
0
            gCMSOutputProfile = GetCMSsRGBProfile();
2123
0
        }
2124
0
2125
0
        if (!gCMSOutputProfile) {
2126
0
            void* mem = nullptr;
2127
0
            size_t size = 0;
2128
0
2129
0
            GetCMSOutputProfileData(mem, size);
2130
0
            if ((mem != nullptr) && (size > 0)) {
2131
0
                gCMSOutputProfile = qcms_profile_from_memory(mem, size);
2132
0
                free(mem);
2133
0
            }
2134
0
        }
2135
0
2136
0
        /* Determine if the profile looks bogus. If so, close the profile
2137
0
         * and use sRGB instead. See bug 460629, */
2138
0
        if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
2139
0
            NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
2140
0
                         "Builtin sRGB profile tagged as bogus!!!");
2141
0
            qcms_profile_release(gCMSOutputProfile);
2142
0
            gCMSOutputProfile = nullptr;
2143
0
        }
2144
0
2145
0
        if (!gCMSOutputProfile) {
2146
0
            gCMSOutputProfile = GetCMSsRGBProfile();
2147
0
        }
2148
0
        /* Precache the LUT16 Interpolations for the output profile. See
2149
0
           bug 444661 for details. */
2150
0
        qcms_profile_precache_output_transform(gCMSOutputProfile);
2151
0
    }
2152
0
}
2153
2154
qcms_profile *
2155
gfxPlatform::GetCMSOutputProfile()
2156
0
{
2157
0
    return gCMSOutputProfile;
2158
0
}
2159
2160
qcms_profile *
2161
gfxPlatform::GetCMSsRGBProfile()
2162
0
{
2163
0
    if (!gCMSsRGBProfile) {
2164
0
2165
0
        /* Create the profile using qcms. */
2166
0
        gCMSsRGBProfile = qcms_profile_sRGB();
2167
0
    }
2168
0
    return gCMSsRGBProfile;
2169
0
}
2170
2171
qcms_transform *
2172
gfxPlatform::GetCMSRGBTransform()
2173
0
{
2174
0
    if (!gCMSRGBTransform && !gCMSRGBTransformFailed) {
2175
0
        qcms_profile *inProfile, *outProfile;
2176
0
        outProfile = GetCMSOutputProfile();
2177
0
        inProfile = GetCMSsRGBProfile();
2178
0
2179
0
        if (!inProfile || !outProfile)
2180
0
            return nullptr;
2181
0
2182
0
        gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
2183
0
                                              outProfile, QCMS_DATA_RGB_8,
2184
0
                                             QCMS_INTENT_PERCEPTUAL);
2185
0
        if (!gCMSRGBTransform) {
2186
0
            gCMSRGBTransformFailed = true;
2187
0
        }
2188
0
    }
2189
0
2190
0
    return gCMSRGBTransform;
2191
0
}
2192
2193
qcms_transform *
2194
gfxPlatform::GetCMSInverseRGBTransform()
2195
0
{
2196
0
    if (!gCMSInverseRGBTransform) {
2197
0
        qcms_profile *inProfile, *outProfile;
2198
0
        inProfile = GetCMSOutputProfile();
2199
0
        outProfile = GetCMSsRGBProfile();
2200
0
2201
0
        if (!inProfile || !outProfile)
2202
0
            return nullptr;
2203
0
2204
0
        gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
2205
0
                                                     outProfile, QCMS_DATA_RGB_8,
2206
0
                                                     QCMS_INTENT_PERCEPTUAL);
2207
0
    }
2208
0
2209
0
    return gCMSInverseRGBTransform;
2210
0
}
2211
2212
qcms_transform *
2213
gfxPlatform::GetCMSRGBATransform()
2214
0
{
2215
0
    if (!gCMSRGBATransform) {
2216
0
        qcms_profile *inProfile, *outProfile;
2217
0
        outProfile = GetCMSOutputProfile();
2218
0
        inProfile = GetCMSsRGBProfile();
2219
0
2220
0
        if (!inProfile || !outProfile)
2221
0
            return nullptr;
2222
0
2223
0
        gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
2224
0
                                               outProfile, QCMS_DATA_RGBA_8,
2225
0
                                               QCMS_INTENT_PERCEPTUAL);
2226
0
    }
2227
0
2228
0
    return gCMSRGBATransform;
2229
0
}
2230
2231
/* Shuts down various transforms and profiles for CMS. */
2232
static void ShutdownCMS()
2233
0
{
2234
0
2235
0
    if (gCMSRGBTransform) {
2236
0
        qcms_transform_release(gCMSRGBTransform);
2237
0
        gCMSRGBTransform = nullptr;
2238
0
    }
2239
0
    if (gCMSInverseRGBTransform) {
2240
0
        qcms_transform_release(gCMSInverseRGBTransform);
2241
0
        gCMSInverseRGBTransform = nullptr;
2242
0
    }
2243
0
    if (gCMSRGBATransform) {
2244
0
        qcms_transform_release(gCMSRGBATransform);
2245
0
        gCMSRGBATransform = nullptr;
2246
0
    }
2247
0
    if (gCMSOutputProfile) {
2248
0
        qcms_profile_release(gCMSOutputProfile);
2249
0
2250
0
        // handle the aliased case
2251
0
        if (gCMSsRGBProfile == gCMSOutputProfile)
2252
0
            gCMSsRGBProfile = nullptr;
2253
0
        gCMSOutputProfile = nullptr;
2254
0
    }
2255
0
    if (gCMSsRGBProfile) {
2256
0
        qcms_profile_release(gCMSsRGBProfile);
2257
0
        gCMSsRGBProfile = nullptr;
2258
0
    }
2259
0
2260
0
    // Reset the state variables
2261
0
    gCMSMode = eCMSMode_Off;
2262
0
    gCMSInitialized = false;
2263
0
}
2264
2265
// default SetupClusterBoundaries, based on Unicode properties;
2266
// platform subclasses may override if they wish
2267
void
2268
gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
2269
0
{
2270
0
    if (aTextRun->GetFlags() & gfx::ShapedTextFlags::TEXT_IS_8BIT) {
2271
0
        // 8-bit text doesn't have clusters.
2272
0
        // XXX is this true in all languages???
2273
0
        // behdad: don't think so.  Czech for example IIRC has a
2274
0
        // 'ch' grapheme.
2275
0
        // jfkthame: but that's not expected to behave as a grapheme cluster
2276
0
        // for selection/editing/etc.
2277
0
        return;
2278
0
    }
2279
0
2280
0
    aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
2281
0
}
2282
2283
int32_t
2284
gfxPlatform::GetBidiNumeralOption()
2285
0
{
2286
0
    if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
2287
0
        mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
2288
0
    }
2289
0
    return mBidiNumeralOption;
2290
0
}
2291
2292
/* static */ void
2293
gfxPlatform::FlushFontAndWordCaches()
2294
0
{
2295
0
    gfxFontCache *fontCache = gfxFontCache::GetCache();
2296
0
    if (fontCache) {
2297
0
        fontCache->AgeAllGenerations();
2298
0
        fontCache->FlushShapedWordCaches();
2299
0
    }
2300
0
2301
0
    gfxPlatform::PurgeSkiaFontCache();
2302
0
}
2303
2304
/* static */ void
2305
gfxPlatform::ForceGlobalReflow()
2306
0
{
2307
0
    MOZ_ASSERT(NS_IsMainThread());
2308
0
    if (XRE_IsParentProcess()) {
2309
0
        // Modify a preference that will trigger reflow everywhere (in all
2310
0
        // content processes, as well as the parent).
2311
0
        static const char kPrefName[] = "font.internaluseonly.changed";
2312
0
        bool fontInternalChange = Preferences::GetBool(kPrefName, false);
2313
0
        Preferences::SetBool(kPrefName, !fontInternalChange);
2314
0
    } else {
2315
0
        // Send a notification that will be observed by PresShells in this
2316
0
        // process only.
2317
0
        nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
2318
0
        if (obs) {
2319
0
            obs->NotifyObservers(nullptr, "font-info-updated", nullptr);
2320
0
        }
2321
0
    }
2322
0
}
2323
2324
void
2325
gfxPlatform::FontsPrefsChanged(const char *aPref)
2326
0
{
2327
0
    NS_ASSERTION(aPref != nullptr, "null preference");
2328
0
    if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
2329
0
        mAllowDownloadableFonts = UNINITIALIZED_VALUE;
2330
0
    } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
2331
0
        mFallbackUsesCmaps = UNINITIALIZED_VALUE;
2332
0
    } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
2333
0
        mWordCacheCharLimit = UNINITIALIZED_VALUE;
2334
0
        FlushFontAndWordCaches();
2335
0
    } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
2336
0
        mWordCacheMaxEntries = UNINITIALIZED_VALUE;
2337
0
        FlushFontAndWordCaches();
2338
0
    } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
2339
0
        mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
2340
0
        FlushFontAndWordCaches();
2341
0
    } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
2342
0
        mBidiNumeralOption = UNINITIALIZED_VALUE;
2343
0
    } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
2344
0
        mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
2345
0
        gfxFontCache::GetCache()->AgeAllGenerations();
2346
0
        gfxFontCache::GetCache()->NotifyGlyphsChanged();
2347
0
    }
2348
0
}
2349
2350
2351
mozilla::LogModule*
2352
gfxPlatform::GetLog(eGfxLog aWhichLog)
2353
0
{
2354
0
    // logs shared across gfx
2355
0
    static LazyLogModule sFontlistLog("fontlist");
2356
0
    static LazyLogModule sFontInitLog("fontinit");
2357
0
    static LazyLogModule sTextrunLog("textrun");
2358
0
    static LazyLogModule sTextrunuiLog("textrunui");
2359
0
    static LazyLogModule sCmapDataLog("cmapdata");
2360
0
    static LazyLogModule sTextPerfLog("textperf");
2361
0
2362
0
    switch (aWhichLog) {
2363
0
    case eGfxLog_fontlist:
2364
0
        return sFontlistLog;
2365
0
    case eGfxLog_fontinit:
2366
0
        return sFontInitLog;
2367
0
    case eGfxLog_textrun:
2368
0
        return sTextrunLog;
2369
0
    case eGfxLog_textrunui:
2370
0
        return sTextrunuiLog;
2371
0
    case eGfxLog_cmapdata:
2372
0
        return sCmapDataLog;
2373
0
    case eGfxLog_textperf:
2374
0
        return sTextPerfLog;
2375
0
    }
2376
0
2377
0
    MOZ_ASSERT_UNREACHABLE("Unexpected log type");
2378
0
    return nullptr;
2379
0
}
2380
2381
RefPtr<mozilla::gfx::DrawTarget>
2382
gfxPlatform::ScreenReferenceDrawTarget()
2383
0
{
2384
0
  return (mScreenReferenceDrawTarget)
2385
0
           ? mScreenReferenceDrawTarget
2386
0
           : gPlatform->CreateOffscreenContentDrawTarget(
2387
0
               IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
2388
0
}
2389
2390
mozilla::gfx::SurfaceFormat
2391
gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
2392
0
{
2393
0
  switch (aContent) {
2394
0
  case gfxContentType::COLOR:
2395
0
    switch (GetOffscreenFormat()) {
2396
0
    case SurfaceFormat::A8R8G8B8_UINT32:
2397
0
      return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2398
0
    case SurfaceFormat::X8R8G8B8_UINT32:
2399
0
      return mozilla::gfx::SurfaceFormat::B8G8R8X8;
2400
0
    case SurfaceFormat::R5G6B5_UINT16:
2401
0
      return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
2402
0
    default:
2403
0
      MOZ_ASSERT_UNREACHABLE("unknown gfxImageFormat for "
2404
0
                             "gfxContentType::COLOR");
2405
0
      return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2406
0
    }
2407
0
  case gfxContentType::ALPHA:
2408
0
    return mozilla::gfx::SurfaceFormat::A8;
2409
0
  case gfxContentType::COLOR_ALPHA:
2410
0
    return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2411
0
  default:
2412
0
    MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2413
0
    return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2414
0
  }
2415
0
}
2416
2417
gfxImageFormat
2418
gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
2419
0
{
2420
0
  switch (aContent) {
2421
0
  case gfxContentType::COLOR:
2422
0
    return GetOffscreenFormat();
2423
0
  case gfxContentType::ALPHA:
2424
0
    return SurfaceFormat::A8;
2425
0
  case gfxContentType::COLOR_ALPHA:
2426
0
    return SurfaceFormat::A8R8G8B8_UINT32;
2427
0
  default:
2428
0
    MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2429
0
    return SurfaceFormat::A8R8G8B8_UINT32;
2430
0
  }
2431
0
}
2432
2433
/**
2434
 * There are a number of layers acceleration (or layers in general) preferences
2435
 * that should be consistent for the lifetime of the application (bug 840967).
2436
 * As such, we will evaluate them all as soon as one of them is evaluated
2437
 * and remember the values.  Changing these preferences during the run will
2438
 * not have any effect until we restart.
2439
 */
2440
static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
2441
static bool sLayersHardwareVideoDecodingFailed = false;
2442
static bool sBufferRotationCheckPref = true;
2443
2444
static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
2445
2446
void VideoDecodingFailedChangedCallback(const char* aPref, void*)
2447
0
{
2448
0
  sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
2449
0
  gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
2450
0
}
2451
2452
void
2453
gfxPlatform::UpdateCanUseHardwareVideoDecoding()
2454
0
{
2455
0
  if (XRE_IsParentProcess()) {
2456
0
    gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
2457
0
  }
2458
0
}
2459
2460
void
2461
gfxPlatform::InitAcceleration()
2462
0
{
2463
0
  if (sLayersAccelerationPrefsInitialized) {
2464
0
    return;
2465
0
  }
2466
0
2467
0
  InitCompositorAccelerationPrefs();
2468
0
2469
0
  // If this is called for the first time on a non-main thread, we're screwed.
2470
0
  // At the moment there's no explicit guarantee that the main thread calls
2471
0
  // this before the compositor thread, but let's at least make the assumption
2472
0
  // explicit.
2473
0
  MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2474
0
2475
0
  gfxPrefs::GetSingleton();
2476
0
2477
0
  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
2478
0
  nsCString discardFailureId;
2479
0
  int32_t status;
2480
0
2481
0
  if (XRE_IsParentProcess()) {
2482
0
    gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
2483
0
    gfxVars::SetOffscreenFormat(GetOffscreenFormat());
2484
0
    gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
2485
0
              RequiresAcceleratedGLContextForCompositorOGL());
2486
#ifdef XP_WIN
2487
    if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
2488
                                               discardFailureId, &status))) {
2489
      gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
2490
    } else {
2491
      // If we couldn't properly evaluate the status, err on the side
2492
      // of caution and give this functionality to the user.
2493
      gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
2494
      gfxVars::SetAllowD3D11KeyedMutex(true);
2495
    }
2496
#endif
2497
  }
2498
0
2499
0
  if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
2500
#ifdef XP_WIN
2501
      Preferences::GetBool("media.wmf.dxva.enabled", true) &&
2502
#endif
2503
0
      NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
2504
0
                                               discardFailureId, &status))) {
2505
0
      if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) {
2506
0
        sLayersSupportsHardwareVideoDecoding = true;
2507
0
      }
2508
0
  }
2509
0
2510
0
  sLayersAccelerationPrefsInitialized = true;
2511
0
2512
0
  if (XRE_IsParentProcess()) {
2513
0
    Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback,
2514
0
                                         "media.hardware-video-decoding.failed");
2515
0
    InitGPUProcessPrefs();
2516
0
  }
2517
0
}
2518
2519
void
2520
gfxPlatform::InitGPUProcessPrefs()
2521
0
{
2522
0
  // We want to hide this from about:support, so only set a default if the
2523
0
  // pref is known to be true.
2524
0
  if (!gfxPrefs::GPUProcessEnabled() && !gfxPrefs::GPUProcessForceEnabled()) {
2525
0
    return;
2526
0
  }
2527
0
2528
0
  FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
2529
0
2530
0
  // We require E10S - otherwise, there is very little benefit to the GPU
2531
0
  // process, since the UI process must still use acceleration for
2532
0
  // performance.
2533
0
  if (!BrowserTabsRemoteAutostart()) {
2534
0
    gpuProc.DisableByDefault(
2535
0
      FeatureStatus::Unavailable,
2536
0
      "Multi-process mode is not enabled",
2537
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_E10S"));
2538
0
  } else {
2539
0
    gpuProc.SetDefaultFromPref(
2540
0
      gfxPrefs::GetGPUProcessEnabledPrefName(),
2541
0
      true,
2542
0
      gfxPrefs::GetGPUProcessEnabledPrefDefault());
2543
0
  }
2544
0
2545
0
  if (gfxPrefs::GPUProcessForceEnabled()) {
2546
0
    gpuProc.UserForceEnable("User force-enabled via pref");
2547
0
  }
2548
0
2549
0
  if (IsHeadless()) {
2550
0
    gpuProc.ForceDisable(
2551
0
      FeatureStatus::Blocked,
2552
0
      "Headless mode is enabled",
2553
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_HEADLESS_MODE"));
2554
0
    return;
2555
0
  }
2556
0
  if (InSafeMode()) {
2557
0
    gpuProc.ForceDisable(
2558
0
      FeatureStatus::Blocked,
2559
0
      "Safe-mode is enabled",
2560
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
2561
0
    return;
2562
0
  }
2563
0
  if (gfxPrefs::LayerScopeEnabled()) {
2564
0
    gpuProc.ForceDisable(
2565
0
      FeatureStatus::Blocked,
2566
0
      "LayerScope does not work in the GPU process",
2567
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_LAYERSCOPE"));
2568
0
    return;
2569
0
  }
2570
0
}
2571
2572
void
2573
gfxPlatform::InitCompositorAccelerationPrefs()
2574
0
{
2575
0
  const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
2576
0
2577
0
  FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
2578
0
2579
0
  // Base value - does the platform allow acceleration?
2580
0
  if (feature.SetDefault(AccelerateLayersByDefault(),
2581
0
                         FeatureStatus::Blocked,
2582
0
                         "Acceleration blocked by platform"))
2583
0
  {
2584
0
    if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) {
2585
0
      feature.UserDisable("Disabled by pref",
2586
0
                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
2587
0
    } else if (acceleratedEnv && *acceleratedEnv == '0') {
2588
0
      feature.UserDisable("Disabled by envvar",
2589
0
                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_ENV"));
2590
0
    }
2591
0
  } else {
2592
0
    if (acceleratedEnv && *acceleratedEnv == '1') {
2593
0
      feature.UserEnable("Enabled by envvar");
2594
0
    }
2595
0
  }
2596
0
2597
0
  // This has specific meaning elsewhere, so we always record it.
2598
0
  if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
2599
0
    feature.UserForceEnable("Force-enabled by pref");
2600
0
  }
2601
0
2602
0
  // Safe, headless, and record/replay modes override everything.
2603
0
  if (InSafeMode()) {
2604
0
    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
2605
0
                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
2606
0
  }
2607
0
  if (IsHeadless()) {
2608
0
    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by headless mode",
2609
0
                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_HEADLESSMODE"));
2610
0
  }
2611
0
  if (recordreplay::IsRecordingOrReplaying()) {
2612
0
    feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by recording/replaying",
2613
0
                         NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_RECORDREPLAY"));
2614
0
  }
2615
0
}
2616
2617
/*static*/ bool
2618
gfxPlatform::WebRenderPrefEnabled()
2619
0
{
2620
0
  return gfxPrefs::WebRenderAll() || gfxPrefs::WebRenderEnabledDoNotUseDirectly();
2621
0
}
2622
2623
/*static*/ bool
2624
gfxPlatform::WebRenderEnvvarEnabled()
2625
0
{
2626
0
  const char* env = PR_GetEnv("MOZ_WEBRENDER");
2627
0
  return (env && *env == '1');
2628
0
}
2629
2630
/* This is a pretty conservative check for having a battery.
2631
 * For now we'd rather err on the side of thinking we do. */
2632
static bool HasBattery()
2633
0
{
2634
#ifdef XP_WIN
2635
  SYSTEM_POWER_STATUS status;
2636
  const BYTE NO_SYSTEM_BATTERY = 128;
2637
  if (GetSystemPowerStatus(&status)) {
2638
    if (status.BatteryFlag == NO_SYSTEM_BATTERY) {
2639
      return false;
2640
    }
2641
  }
2642
#endif
2643
  return true;
2644
0
}
2645
2646
void
2647
gfxPlatform::InitWebRenderConfig()
2648
0
{
2649
0
  bool prefEnabled = WebRenderPrefEnabled();
2650
0
  bool envvarEnabled = WebRenderEnvvarEnabled();
2651
0
2652
0
  // On Nightly:
2653
0
  //   WR? WR+   => means WR was enabled via gfx.webrender.all.qualified
2654
0
  //   WR! WR+   => means WR was enabled via gfx.webrender.{all,enabled} or envvar
2655
0
  // On Beta/Release:
2656
0
  //   WR? WR+   => means WR was enabled via gfx.webrender.all.qualified on qualified hardware
2657
0
  //   WR! WR+   => means WR was enabled via envvar, possibly on unqualified hardware.
2658
0
  // In all cases WR- means WR was not enabled, for one of many possible reasons.
2659
0
  ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled);
2660
0
  if (!XRE_IsParentProcess()) {
2661
0
    // The parent process runs through all the real decision-making code
2662
0
    // later in this function. For other processes we still want to report
2663
0
    // the state of the feature for crash reports.
2664
0
    if (gfxVars::UseWebRender()) {
2665
0
      reporter.SetSuccessful();
2666
0
    }
2667
0
    return;
2668
0
  }
2669
0
2670
0
  FeatureState& featureWebRenderQualified = gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED);
2671
0
  featureWebRenderQualified.EnableByDefault();
2672
0
  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
2673
0
  nsCString failureId;
2674
0
  int32_t status;
2675
0
  if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER,
2676
0
                                             failureId, &status))) {
2677
0
    if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
2678
0
      featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2679
0
                                         "No qualified hardware",
2680
0
                                         failureId);
2681
0
    } else if (HasBattery()) {
2682
0
      featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2683
0
                                         "Has battery",
2684
0
                                         NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_HAS_BATTERY"));
2685
0
    } else {
2686
0
      nsAutoString adapterVendorID;
2687
0
      gfxInfo->GetAdapterVendorID(adapterVendorID);
2688
0
      if (adapterVendorID != u"0x10de") {
2689
0
        featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2690
0
                                         "Not Nvidia",
2691
0
                                         NS_LITERAL_CSTRING("FEATURE_FAILURE_NOT_NVIDIA"));
2692
0
      } else {
2693
0
        nsAutoString adapterDeviceID;
2694
0
        gfxInfo->GetAdapterDeviceID(adapterDeviceID);
2695
0
        nsresult valid;
2696
0
        int32_t deviceID = adapterDeviceID.ToInteger(&valid, 16);
2697
0
        if (valid != NS_OK) {
2698
0
          featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2699
0
                                            "Bad device id",
2700
0
                                            NS_LITERAL_CSTRING("FEATURE_FAILURE_BAD_DEVICE_ID"));
2701
0
        } else if (deviceID < 0x6c0) {
2702
0
           // 0x6c0 is the lowest Fermi device id. Unfortunately some Tesla devices that don't support D3D 10.1
2703
0
           // have higher deviceIDs. They will be included, but blocked by ANGLE.
2704
0
          featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2705
0
                                            "Device too old",
2706
0
                                            NS_LITERAL_CSTRING("FEATURE_FAILURE_DEVICE_TOO_OLD"));
2707
0
        }
2708
0
      }
2709
0
    }
2710
0
  } else {
2711
0
    featureWebRenderQualified.Disable(FeatureStatus::Blocked,
2712
0
                                       "gfxInfo is broken",
2713
0
                                       NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_NO_GFX_INFO"));
2714
0
  }
2715
0
2716
0
  FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
2717
0
2718
0
  featureWebRender.DisableByDefault(
2719
0
      FeatureStatus::OptIn,
2720
0
      "WebRender is an opt-in feature",
2721
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
2722
0
2723
0
  // envvar works everywhere; we need this for testing in CI. Sadly this allows
2724
0
  // beta/release to enable it on unqualified hardware, but at least this is
2725
0
  // harder for the average person than flipping a pref.
2726
0
  if (envvarEnabled) {
2727
0
    featureWebRender.UserEnable("Force enabled by envvar");
2728
0
2729
0
  // gfx.webrender.enabled and gfx.webrender.all only work on nightly
2730
0
#ifdef NIGHTLY_BUILD
2731
0
  } else if (prefEnabled) {
2732
0
    featureWebRender.UserEnable("Force enabled by pref");
2733
0
#endif
2734
0
2735
0
  // gfx.webrender.all.qualified works on all channels
2736
0
  } else if (gfxPrefs::WebRenderAllQualified()) {
2737
0
    if (featureWebRenderQualified.IsEnabled()) {
2738
0
      featureWebRender.UserEnable("Qualified enabled by pref ");
2739
0
    } else {
2740
0
      featureWebRender.ForceDisable(FeatureStatus::Blocked,
2741
0
                                    "Qualified enable blocked",
2742
0
                                    failureId);
2743
0
    }
2744
0
  }
2745
0
2746
0
  // If the user set the pref to force-disable, let's do that. This will
2747
0
  // override all the other enabling prefs (gfx.webrender.enabled,
2748
0
  // gfx.webrender.all, and gfx.webrender.all.qualified).
2749
0
  if (gfxPrefs::WebRenderForceDisabled()) {
2750
0
    featureWebRender.UserDisable(
2751
0
      "User force-disabled WR",
2752
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_USER_FORCE_DISABLED"));
2753
0
  }
2754
0
2755
0
  // HW_COMPOSITING being disabled implies interfacing with the GPU might break
2756
0
  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
2757
0
    featureWebRender.ForceDisable(
2758
0
      FeatureStatus::Unavailable,
2759
0
      "Hardware compositing is disabled",
2760
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"));
2761
0
  }
2762
0
2763
0
  // WebRender relies on the GPU process when on Windows
2764
#ifdef XP_WIN
2765
  if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2766
    featureWebRender.ForceDisable(
2767
      FeatureStatus::Unavailable,
2768
      "GPU Process is disabled",
2769
      NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
2770
  }
2771
#endif
2772
2773
0
  if (InSafeMode()) {
2774
0
    featureWebRender.ForceDisable(
2775
0
      FeatureStatus::Unavailable,
2776
0
      "Safe-mode is enabled",
2777
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
2778
0
  }
2779
0
2780
#ifndef MOZ_BUILD_WEBRENDER
2781
  featureWebRender.ForceDisable(
2782
    FeatureStatus::Unavailable,
2783
    "Build doesn't include WebRender",
2784
    NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_WEBRENDER"));
2785
#endif
2786
2787
#ifdef XP_WIN
2788
  if (Preferences::GetBool("gfx.webrender.force-angle", false)) {
2789
    if (!gfxConfig::IsEnabled(Feature::D3D11_HW_ANGLE)) {
2790
      featureWebRender.ForceDisable(
2791
        FeatureStatus::Unavailable,
2792
        "ANGLE is disabled",
2793
        NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED"));
2794
    } else {
2795
      gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER));
2796
    }
2797
  }
2798
#endif
2799
2800
0
  if (Preferences::GetBool("gfx.webrender.program-binary", false)) {
2801
0
    gfxVars::SetUseWebRenderProgramBinary(gfxConfig::IsEnabled(Feature::WEBRENDER));
2802
0
    if (Preferences::GetBool("gfx.webrender.program-binary-disk", false)) {
2803
0
      gfxVars::SetUseWebRenderProgramBinaryDisk(gfxConfig::IsEnabled(Feature::WEBRENDER));
2804
0
    }
2805
0
  }
2806
0
2807
#ifdef MOZ_WIDGET_ANDROID
2808
  featureWebRender.ForceDisable(
2809
    FeatureStatus::Unavailable,
2810
    "WebRender not ready for use on Android",
2811
    NS_LITERAL_CSTRING("FEATURE_FAILURE_ANDROID"));
2812
#endif
2813
2814
0
  // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
2815
0
  if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
2816
0
    gfxVars::SetUseWebRender(true);
2817
0
    reporter.SetSuccessful();
2818
0
2819
0
    if (XRE_IsParentProcess()) {
2820
0
      Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
2821
0
                                                 WR_DEBUG_PREF);
2822
0
    }
2823
0
  }
2824
0
2825
#ifdef XP_WIN
2826
  if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) {
2827
    // XXX relax win version to windows 8.
2828
    if (IsWin10OrLater() &&
2829
        gfxVars::UseWebRender() &&
2830
        gfxVars::UseWebRenderANGLE()) {
2831
      gfxVars::SetUseWebRenderDCompWin(true);
2832
    }
2833
  }
2834
#endif
2835
}
2836
2837
void
2838
gfxPlatform::InitOMTPConfig()
2839
0
{
2840
0
  ScopedGfxFeatureReporter reporter("OMTP");
2841
0
2842
0
  FeatureState& omtp = gfxConfig::GetFeature(Feature::OMTP);
2843
0
  int32_t paintWorkerCount = PaintThread::CalculatePaintWorkerCount();
2844
0
2845
0
  if (!XRE_IsParentProcess()) {
2846
0
    // The parent process runs through all the real decision-making code
2847
0
    // later in this function. For other processes we still want to report
2848
0
    // the state of the feature for crash reports.
2849
0
    if (gfxVars::UseOMTP()) {
2850
0
      reporter.SetSuccessful(paintWorkerCount);
2851
0
    }
2852
0
    return;
2853
0
  }
2854
0
2855
0
  omtp.SetDefaultFromPref(
2856
0
    "layers.omtp.enabled",
2857
0
    true,
2858
0
    Preferences::GetBool("layers.omtp.enabled", false, PrefValueKind::Default));
2859
0
2860
0
  if (mContentBackend == BackendType::CAIRO) {
2861
0
    omtp.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo",
2862
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
2863
0
  }
2864
0
2865
#ifdef XP_MACOSX
2866
  if (!nsCocoaFeatures::OnYosemiteOrLater()) {
2867
    omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked before OSX 10.10",
2868
                      NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_OSX_MAVERICKS"));
2869
  }
2870
#endif
2871
2872
0
  if (InSafeMode()) {
2873
0
    omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
2874
0
                      NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
2875
0
  }
2876
0
2877
0
  if (omtp.IsEnabled()) {
2878
0
    gfxVars::SetUseOMTP(true);
2879
0
    reporter.SetSuccessful(paintWorkerCount);
2880
0
  }
2881
0
}
2882
2883
bool
2884
gfxPlatform::CanUseHardwareVideoDecoding()
2885
0
{
2886
0
  // this function is called from the compositor thread, so it is not
2887
0
  // safe to init the prefs etc. from here.
2888
0
  MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2889
0
  return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed;
2890
0
}
2891
2892
bool
2893
gfxPlatform::AccelerateLayersByDefault()
2894
0
{
2895
#if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
2896
  return true;
2897
#else
2898
  return false;
2899
0
#endif
2900
0
}
2901
2902
bool
2903
gfxPlatform::BufferRotationEnabled()
2904
0
{
2905
0
  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2906
0
2907
0
  return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2908
0
}
2909
2910
void
2911
gfxPlatform::DisableBufferRotation()
2912
0
{
2913
0
  MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2914
0
2915
0
  sBufferRotationCheckPref = false;
2916
0
}
2917
2918
/* static */ bool
2919
gfxPlatform::UsesOffMainThreadCompositing()
2920
0
{
2921
0
  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
2922
0
    return true;
2923
0
  }
2924
0
2925
0
  static bool firstTime = true;
2926
0
  static bool result = false;
2927
0
2928
0
  if (firstTime) {
2929
0
    MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2930
0
    result =
2931
0
      gfxVars::BrowserTabsRemoteAutostart() ||
2932
0
      !gfxPrefs::LayersOffMainThreadCompositionForceDisabled();
2933
0
#if defined(MOZ_WIDGET_GTK)
2934
0
    // Linux users who chose OpenGL are being grandfathered in to OMTC
2935
0
    result |= gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly();
2936
0
2937
0
#endif
2938
0
    firstTime = false;
2939
0
  }
2940
0
2941
0
  return result;
2942
0
}
2943
2944
bool
2945
gfxPlatform::UsesTiling() const
2946
0
{
2947
0
  bool usesSkia = GetDefaultContentBackend() == BackendType::SKIA;
2948
0
2949
0
  // We can't just test whether the PaintThread is initialized here because
2950
0
  // this function is used when initializing the PaintThread. So instead we
2951
0
  // check the conditions that enable OMTP with parallel painting.
2952
0
  bool usesPOMTP = XRE_IsContentProcess() &&
2953
0
    gfxVars::UseOMTP() &&
2954
0
    (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
2955
0
      gfxPrefs::LayersOMTPPaintWorkers() > 1);
2956
0
2957
0
  return gfxPrefs::LayersTilesEnabled() ||
2958
0
    (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() &&
2959
0
      usesSkia &&
2960
0
      usesPOMTP);
2961
0
}
2962
2963
bool
2964
gfxPlatform::ContentUsesTiling() const
2965
0
{
2966
0
  BackendPrefsData data = GetBackendPrefs();
2967
0
  BackendType contentBackend = GetContentBackendPref(data.mContentBitmask);
2968
0
  if (contentBackend == BackendType::NONE) {
2969
0
    contentBackend = data.mContentDefault;
2970
0
  }
2971
0
2972
0
  bool contentUsesSkia = contentBackend == BackendType::SKIA;
2973
0
  bool contentUsesPOMTP = gfxVars::UseOMTP() &&
2974
0
    (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
2975
0
      gfxPrefs::LayersOMTPPaintWorkers() > 1);
2976
0
2977
0
  return gfxPrefs::LayersTilesEnabled() ||
2978
0
    (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() &&
2979
0
      contentUsesSkia &&
2980
0
      contentUsesPOMTP);
2981
0
}
2982
2983
/***
2984
 * The preference "layout.frame_rate" has 3 meanings depending on the value:
2985
 *
2986
 * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
2987
 *  0 = ASAP mode - used during talos testing.
2988
 *  X = Software vsync at a rate of X times per second.
2989
 */
2990
already_AddRefed<mozilla::gfx::VsyncSource>
2991
gfxPlatform::CreateHardwareVsyncSource()
2992
0
{
2993
0
  RefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
2994
0
  return softwareVsync.forget();
2995
0
}
2996
2997
/* static */ bool
2998
gfxPlatform::IsInLayoutAsapMode()
2999
0
{
3000
0
  // There are 2 modes of ASAP mode.
3001
0
  // 1 is that the refresh driver and compositor are in lock step
3002
0
  // the second is that the compositor goes ASAP and the refresh driver
3003
0
  // goes at whatever the configurated rate is. This only checks the version
3004
0
  // talos uses, which is the refresh driver and compositor are in lockstep.
3005
0
  return gfxPrefs::LayoutFrameRate() == 0;
3006
0
}
3007
3008
/* static */ bool
3009
gfxPlatform::ForceSoftwareVsync()
3010
0
{
3011
0
  return gfxPrefs::LayoutFrameRate() > 0 || recordreplay::IsRecordingOrReplaying();
3012
0
}
3013
3014
/* static */ int
3015
gfxPlatform::GetSoftwareVsyncRate()
3016
0
{
3017
0
  int preferenceRate = gfxPrefs::LayoutFrameRate();
3018
0
  if (preferenceRate <= 0) {
3019
0
    return gfxPlatform::GetDefaultFrameRate();
3020
0
  }
3021
0
  return preferenceRate;
3022
0
}
3023
3024
/* static */ int
3025
gfxPlatform::GetDefaultFrameRate()
3026
0
{
3027
0
  return 60;
3028
0
}
3029
3030
void
3031
gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj)
3032
0
{
3033
0
  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
3034
0
    aObj.DefineProperty("AzureCanvasBackend (UI Process)", GetBackendName(mPreferredCanvasBackend));
3035
0
    aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)", GetBackendName(mFallbackCanvasBackend));
3036
0
    aObj.DefineProperty("AzureContentBackend (UI Process)", GetBackendName(mContentBackend));
3037
0
3038
0
    // Assume content process' backend prefs.
3039
0
    BackendPrefsData data = GetBackendPrefs();
3040
0
    BackendType canvasBackend = GetCanvasBackendPref(data.mCanvasBitmask);
3041
0
    if (canvasBackend == BackendType::NONE) {
3042
0
      canvasBackend = data.mCanvasDefault;
3043
0
    }
3044
0
    BackendType contentBackend = GetContentBackendPref(data.mContentBitmask);
3045
0
    if (contentBackend == BackendType::NONE) {
3046
0
      contentBackend = data.mContentDefault;
3047
0
    }
3048
0
    aObj.DefineProperty("AzureCanvasBackend", GetBackendName(canvasBackend));
3049
0
    aObj.DefineProperty("AzureContentBackend", GetBackendName(contentBackend));
3050
0
  } else {
3051
0
    aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
3052
0
    aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
3053
0
    aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
3054
0
  }
3055
0
3056
0
  aObj.DefineProperty("AzureCanvasAccelerated", AllowOpenGLCanvas());
3057
0
}
3058
3059
void
3060
gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj)
3061
0
{
3062
0
  if (!gfxPlatform::AsyncPanZoomEnabled()) {
3063
0
    return;
3064
0
  }
3065
0
3066
0
  if (SupportsApzWheelInput()) {
3067
0
    aObj.DefineProperty("ApzWheelInput", 1);
3068
0
  }
3069
0
3070
0
  if (SupportsApzTouchInput()) {
3071
0
    aObj.DefineProperty("ApzTouchInput", 1);
3072
0
  }
3073
0
3074
0
  if (SupportsApzDragInput()) {
3075
0
    aObj.DefineProperty("ApzDragInput", 1);
3076
0
  }
3077
0
3078
0
  if (SupportsApzKeyboardInput() && !gfxPrefs::AccessibilityBrowseWithCaret()) {
3079
0
    aObj.DefineProperty("ApzKeyboardInput", 1);
3080
0
  }
3081
0
3082
0
  if (SupportsApzAutoscrolling()) {
3083
0
    aObj.DefineProperty("ApzAutoscrollInput", 1);
3084
0
  }
3085
0
}
3086
3087
void
3088
gfxPlatform::GetTilesSupportInfo(mozilla::widget::InfoObject& aObj)
3089
0
{
3090
0
  if (!gfxPrefs::LayersTilesEnabled()) {
3091
0
    return;
3092
0
  }
3093
0
3094
0
  IntSize tileSize = gfxVars::TileSize();
3095
0
  aObj.DefineProperty("TileHeight", tileSize.height);
3096
0
  aObj.DefineProperty("TileWidth", tileSize.width);
3097
0
}
3098
3099
/*static*/ bool
3100
gfxPlatform::AsyncPanZoomEnabled()
3101
0
{
3102
0
#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
3103
0
  // For XUL applications (everything but Firefox on Android)
3104
0
  // we only want to use APZ when E10S is enabled. If
3105
0
  // we ever get input events off the main thread we can consider relaxing
3106
0
  // this requirement.
3107
0
  if (!BrowserTabsRemoteAutostart()) {
3108
0
    return false;
3109
0
  }
3110
0
#endif
3111
#ifdef MOZ_WIDGET_ANDROID
3112
  return true;
3113
#else
3114
0
  if (!gfxPrefs::SingletonExists()) {
3115
0
    // Make sure the gfxPrefs has been initialized before reading from it.
3116
0
    MOZ_ASSERT(NS_IsMainThread());
3117
0
    gfxPrefs::GetSingleton();
3118
0
  }
3119
0
  return gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly();
3120
0
#endif
3121
0
}
3122
3123
/*static*/ bool
3124
gfxPlatform::PerfWarnings()
3125
0
{
3126
0
  return gfxPrefs::PerfWarnings();
3127
0
}
3128
3129
void
3130
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
3131
0
{
3132
0
  if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING)) {
3133
0
    aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
3134
0
  }
3135
0
  else {
3136
0
    static int tell_me_once = 0;
3137
0
    if (!tell_me_once) {
3138
0
      NS_WARNING("OpenGL-accelerated layers are not supported on this system");
3139
0
      tell_me_once = 1;
3140
0
    }
3141
#ifdef MOZ_WIDGET_ANDROID
3142
    MOZ_CRASH("OpenGL-accelerated layers are a hard requirement on this platform. "
3143
              "Cannot continue without support for them");
3144
#endif
3145
  }
3146
0
}
3147
3148
void
3149
gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends)
3150
0
{
3151
0
  if (useAcceleration) {
3152
0
    GetAcceleratedCompositorBackends(aBackends);
3153
0
  }
3154
0
  aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
3155
0
}
3156
3157
void
3158
gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend)
3159
0
{
3160
0
  if (mCompositorBackend == aBackend) {
3161
0
    return;
3162
0
  }
3163
0
3164
0
  if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
3165
0
    gfxCriticalNote << "Compositors might be mixed ("
3166
0
      << int(mCompositorBackend) << "," << int(aBackend) << ")";
3167
0
  }
3168
0
3169
0
  // Set the backend before we notify so it's available immediately.
3170
0
  mCompositorBackend = aBackend;
3171
0
3172
0
  // Notify that we created a compositor, so telemetry can update.
3173
0
  NS_DispatchToMainThread(
3174
0
    NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] {
3175
0
      if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
3176
0
        obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
3177
0
      }
3178
0
    }));
3179
0
}
3180
3181
/* static */ void
3182
gfxPlatform::NotifyGPUProcessDisabled()
3183
0
{
3184
0
  if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
3185
0
    gfxConfig::GetFeature(Feature::WEBRENDER).ForceDisable(
3186
0
      FeatureStatus::Unavailable,
3187
0
      "GPU Process is disabled",
3188
0
      NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
3189
0
    gfxVars::SetUseWebRender(false);
3190
0
  }
3191
0
}
3192
3193
void
3194
gfxPlatform::FetchAndImportContentDeviceData()
3195
0
{
3196
0
  MOZ_ASSERT(XRE_IsContentProcess());
3197
0
3198
0
  if (gContentDeviceInitData) {
3199
0
    ImportContentDeviceData(*gContentDeviceInitData);
3200
0
    return;
3201
0
  }
3202
0
3203
0
  mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
3204
0
3205
0
  mozilla::gfx::ContentDeviceData data;
3206
0
  cc->SendGetGraphicsDeviceInitData(&data);
3207
0
3208
0
  ImportContentDeviceData(data);
3209
0
}
3210
3211
void
3212
gfxPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
3213
0
{
3214
0
  MOZ_ASSERT(XRE_IsContentProcess());
3215
0
3216
0
  const DevicePrefs& prefs = aData.prefs();
3217
0
  gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
3218
0
  gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
3219
0
}
3220
3221
void
3222
gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut)
3223
0
{
3224
0
  MOZ_ASSERT(XRE_IsParentProcess());
3225
0
3226
0
  // Make sure our settings are synchronized from the GPU process.
3227
0
  GPUProcessManager::Get()->EnsureGPUReady();
3228
0
3229
0
  aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
3230
0
  aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
3231
0
}
3232
3233
void
3234
gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
3235
0
{
3236
0
  MOZ_ASSERT(XRE_IsParentProcess());
3237
0
3238
0
  gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
3239
0
  gfxConfig::ImportChange(Feature::ADVANCED_LAYERS, aData.advancedLayers());
3240
0
}
3241
3242
bool
3243
gfxPlatform::SupportsApzTouchInput() const
3244
0
{
3245
0
  return dom::TouchEvent::PrefEnabled(nullptr);
3246
0
}
3247
3248
bool
3249
gfxPlatform::SupportsApzDragInput() const
3250
0
{
3251
0
  return gfxPrefs::APZDragEnabled();
3252
0
}
3253
3254
bool
3255
gfxPlatform::SupportsApzKeyboardInput() const
3256
0
{
3257
0
  return gfxPrefs::APZKeyboardEnabled();
3258
0
}
3259
3260
bool
3261
gfxPlatform::SupportsApzAutoscrolling() const
3262
0
{
3263
0
  return gfxPrefs::APZAutoscrollEnabled();
3264
0
}
3265
3266
void
3267
gfxPlatform::InitOpenGLConfig()
3268
0
{
3269
  #ifdef XP_WIN
3270
  // Don't enable by default on Windows, since it could show up in about:support even
3271
  // though it'll never get used. Only attempt if user enables the pref
3272
  if (!Preferences::GetBool("layers.prefer-opengl")){
3273
    return;
3274
  }
3275
  #endif
3276
3277
0
  FeatureState& openGLFeature = gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
3278
0
3279
0
  // Check to see hw comp supported
3280
0
  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3281
0
    openGLFeature.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
3282
0
                           NS_LITERAL_CSTRING("FEATURE_FAILURE_OPENGL_NEED_HWCOMP"));
3283
0
    return;
3284
0
  }
3285
0
3286
  #ifdef XP_WIN
3287
  openGLFeature.SetDefaultFromPref(
3288
    gfxPrefs::GetLayersPreferOpenGLPrefName(),
3289
    true,
3290
    gfxPrefs::GetLayersPreferOpenGLPrefDefault());
3291
  #else
3292
0
    openGLFeature.EnableByDefault();
3293
0
  #endif
3294
0
3295
0
  // When layers acceleration is force-enabled, enable it even for blacklisted
3296
0
  // devices.
3297
0
  if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
3298
0
    openGLFeature.UserForceEnable("Force-enabled by pref");
3299
0
    return;
3300
0
  }
3301
0
3302
0
  nsCString message;
3303
0
  nsCString failureId;
3304
0
  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) {
3305
0
    openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
3306
0
  }
3307
0
}
3308
3309
bool
3310
gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId)
3311
0
{
3312
0
  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
3313
0
  if (!gfxInfo) {
3314
0
    return true;
3315
0
  }
3316
0
3317
0
  int32_t status;
3318
0
  if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
3319
0
      status != nsIGfxInfo::FEATURE_STATUS_OK)
3320
0
  {
3321
0
    aOutMessage->AssignLiteral("#BLOCKLIST_");
3322
0
    aOutMessage->AppendASCII(aFailureId.get());
3323
0
    return false;
3324
0
  }
3325
0
3326
0
  return true;
3327
0
}