Bug 920160 - Add prefs for SkiaGL cache size r=snorp
authorGeorge Wright <gwright@mozilla.com>
Tue, 22 Oct 2013 14:15:24 -0500
changeset 151714 ce0759a746fb526db7044b7ab1096e2c08823200
parent 151713 2131ecb804a85720775d4200dad58b4e0781a82e
child 151715 b011488de9e6e3c4fbf4acfd1fd582addcb7a9d1
push id25504
push userphilringnalda@gmail.com
push dateWed, 23 Oct 2013 02:50:41 +0000
treeherdermozilla-central@21d97baadc05 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs920160
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 920160 - Add prefs for SkiaGL cache size r=snorp
b2g/app/b2g.js
gfx/2d/2D.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
gfx/2d/Factory.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
hal/Hal.cpp
hal/Hal.h
hal/fallback/FallbackMemory.cpp
hal/linux/LinuxMemory.cpp
hal/moz.build
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -809,16 +809,19 @@ pref("dom.mozInputMethod.enabled", true)
 // to communicate with a usb cable via adb forward
 pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
 
 // enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases,
 // falling back to Skia/software for smaller canvases
 pref("gfx.canvas.azure.backends", "skia");
 pref("gfx.canvas.azure.accelerated", true);
 
+// Turn on dynamic cache size for Skia
+pref("gfx.canvas.skiagl.dynamic-cache", true);
+
 // Enable Telephony API
 pref("dom.telephony.enabled", true);
 
 // Cell Broadcast API
 pref("dom.cellbroadcast.enabled", true);
 pref("ril.cellbroadcast.disabled", false);
 
 // ICC API
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -993,16 +993,19 @@ public:
   static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder);
 
 #ifdef USE_SKIA_GPU
   static TemporaryRef<DrawTarget>
     CreateDrawTargetSkiaWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
                                                       GrGLInterface* aGrGLInterface,
                                                       const IntSize &aSize,
                                                       SurfaceFormat aFormat);
+
+  static void
+    SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes);
 #endif
 
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
   static TemporaryRef<GlyphRenderingOptions>
     CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting);
 #endif
   static TemporaryRef<DrawTarget>
     CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB);
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -71,66 +71,68 @@ public:
 
   std::vector<SkColor> mColors;
   std::vector<SkScalar> mPositions;
   int mCount;
   ExtendMode mExtendMode;
 };
 
 #ifdef USE_SKIA_GPU
+int DrawTargetSkia::sTextureCacheCount = 256;
+int DrawTargetSkia::sTextureCacheSizeInBytes = 96*1024*1024;
 
 static std::vector<DrawTargetSkia*>&
 GLDrawTargets()
 {
   static std::vector<DrawTargetSkia*> targets;
   return targets;
 }
 
-#define SKIA_MAX_CACHE_ITEMS 256
-
-// 64MB was chosen because it seems we can pass all of our tests
-// on the current hardware (Tegra2) without running out of memory
-#define SKIA_TOTAL_CACHE_SIZE 64*1024*1024
-
-static void
-SetCacheLimits()
+void
+DrawTargetSkia::RebalanceCacheLimits()
 {
+  // Divide the global cache limits equally between all currently active GL-backed
+  // Skia DrawTargets.
   std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
-  uint32_t size = targets.size();
-  if (size == 0)
+  uint32_t targetCount = targets.size();
+  if (targetCount == 0)
     return;
 
-  int individualCacheSize = SKIA_TOTAL_CACHE_SIZE / size;
-  for (uint32_t i = 0; i < size; i++) {
-    targets[i]->SetCacheLimits(SKIA_MAX_CACHE_ITEMS, individualCacheSize);
+  int individualCacheSize = sTextureCacheSizeInBytes / targetCount;
+  for (uint32_t i = 0; i < targetCount; i++) {
+    targets[i]->SetCacheLimits(sTextureCacheCount, individualCacheSize);
   }
-
 }
 
-#undef SKIA_MAX_CACHE_ITEMS
-#undef SKIA_TOTAL_CACHE_SIZE
-
 static void
 AddGLDrawTarget(DrawTargetSkia* target)
 {
   GLDrawTargets().push_back(target);
-  SetCacheLimits();
+  DrawTargetSkia::RebalanceCacheLimits();
 }
 
 static void
 RemoveGLDrawTarget(DrawTargetSkia* target)
 {
   std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
   std::vector<DrawTargetSkia*>::iterator it = std::find(targets.begin(), targets.end(), target);
   if (it != targets.end()) {
     targets.erase(it);
-    SetCacheLimits();
+    DrawTargetSkia::RebalanceCacheLimits();
   }
 }
 
+void
+DrawTargetSkia::SetGlobalCacheLimits(int aCount, int aSizeInBytes)
+{
+  sTextureCacheCount = aCount;
+  sTextureCacheSizeInBytes = aSizeInBytes;
+
+  DrawTargetSkia::RebalanceCacheLimits();
+}
 #endif
 
 DrawTargetSkia::DrawTargetSkia()
   : mSnapshot(nullptr)
 {
 }
 
 DrawTargetSkia::~DrawTargetSkia()
@@ -727,17 +729,16 @@ DrawTargetSkia::InitWithGLContextAndGrGL
 }
 
 void
 DrawTargetSkia::SetCacheLimits(int aCount, int aSizeInBytes)
 {
   MOZ_ASSERT(mGrContext, "No GrContext!");
   mGrContext->setTextureCacheLimits(aCount, aSizeInBytes);
 }
-
 #endif
 
 void
 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   bool isOpaque = false;
   if (aFormat == FORMAT_B8G8R8X8) {
     // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -100,17 +100,19 @@ public:
 
 #ifdef USE_SKIA_GPU
   virtual GenericRefCountedBase* GetGLContext() const MOZ_OVERRIDE { return mGLContext; }
   void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
                                          GrGLInterface* aGrGLInterface,
                                          const IntSize &aSize,
                                          SurfaceFormat aFormat) MOZ_OVERRIDE;
 
-  void SetCacheLimits(int number, int sizeInBytes);
+  void SetCacheLimits(int aCount, int aSizeInBytes);
+  static void SetGlobalCacheLimits(int aCount, int aSizeInBytes);
+  static void RebalanceCacheLimits();
 #endif
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 
@@ -125,16 +127,19 @@ private:
    * These members have inter-dependencies, but do not keep each other alive, so
    * destruction order is very important here: mGrContext uses mGrGLInterface, and
    * through it, uses mGLContext, so it is important that they be declared in the
    * present order.
    */
   RefPtr<GenericRefCountedBase> mGLContext;
   SkRefPtr<GrGLInterface> mGrGLInterface;
   SkRefPtr<GrContext> mGrContext;
+
+  static int sTextureCacheCount;
+  static int sTextureCacheSizeInBytes;
 #endif
 
   IntSize mSize;
   SkRefPtr<SkCanvas> mCanvas;
   SourceSurfaceSkia* mSnapshot;
 };
 
 }
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -508,16 +508,22 @@ Factory::CreateDrawTargetSkiaWithGLConte
                                                            const IntSize &aSize,
                                                            SurfaceFormat aFormat)
 {
   DrawTargetSkia* newDrawTargetSkia = new DrawTargetSkia();
   newDrawTargetSkia->InitWithGLContextAndGrGLInterface(aGLContext, aGrGLInterface, aSize, aFormat);
   RefPtr<DrawTarget> newTarget = newDrawTargetSkia;
   return newTarget;
 }
+
+void
+Factory::SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes)
+{
+    DrawTargetSkia::SetGlobalCacheLimits(aCount, aSizeInBytes);
+}
 #endif // USE_SKIA_GPU
 
 #ifdef USE_SKIA_FREETYPE
 TemporaryRef<GlyphRenderingOptions>
 Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting)
 {
   RefPtr<GlyphRenderingOptionsCairo> options =
     new GlyphRenderingOptionsCairo();
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -57,16 +57,17 @@
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "TexturePoolOGL.h"
 #endif
 
 #ifdef USE_SKIA
+#include "mozilla/Hal.h"
 #include "skia/SkGraphics.h"
 #endif
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
@@ -272,16 +273,20 @@ gfxPlatform::gfxPlatform()
                                  false);
     Preferences::AddBoolVarCache(&mDrawBigImageBorders,
                                  "layers.draw-bigimage-borders",
                                  false);
 
     uint32_t canvasMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA);
     uint32_t contentMask = 1 << BACKEND_CAIRO;
     InitBackendPrefs(canvasMask, contentMask);
+
+#ifdef USE_SKIA
+    InitializeSkiaCaches();
+#endif
 }
 
 gfxPlatform*
 gfxPlatform::GetPlatform()
 {
     if (!gPlatform) {
         Init();
     }
@@ -805,16 +810,49 @@ gfxPlatform::SupportsAzureContentForDraw
 
 bool
 gfxPlatform::UseAcceleratedSkiaCanvas()
 {
   return Preferences::GetBool("gfx.canvas.azure.accelerated", false) &&
          mPreferredCanvasBackend == BACKEND_SKIA;
 }
 
+void
+gfxPlatform::InitializeSkiaCaches()
+{
+#ifdef USE_SKIA_GPU
+  if (UseAcceleratedSkiaCanvas()) {
+    bool usingDynamicCache = Preferences::GetBool("gfx.canvas.skiagl.dynamic-cache", false);
+
+    int cacheItemLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-items", 256);
+    int cacheSizeLimit = Preferences::GetInt("gfx.canvas.skiagl.cache-size", 96);
+
+    // Prefs are in megabytes, but we want the sizes in bytes
+    cacheSizeLimit *= 1024*1024;
+
+    if (usingDynamicCache) {
+      uint32_t totalMemory = mozilla::hal::GetTotalSystemMemory();
+
+      if (totalMemory <= 256*1024*1024) {
+        // We need a very minimal cache on 256 meg devices
+        cacheSizeLimit = 2*1024*1024;
+      } else if (totalMemory > 0) {
+        cacheSizeLimit = totalMemory / 16;
+      }
+    }
+
+#ifdef DEBUG
+    printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
+#endif
+
+    Factory::SetGlobalSkiaCacheLimits(cacheItemLimit, cacheSizeLimit);
+  }
+#endif
+}
+
 already_AddRefed<gfxASurface>
 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
   if (aTarget->GetType() == BACKEND_CAIRO) {
     cairo_surface_t* csurf =
       static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE));
     return gfxASurface::Wrap(csurf);
   }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -273,16 +273,18 @@ public:
     bool SupportsAzureContentForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
 
     bool SupportsAzureContentForType(mozilla::gfx::BackendType aType) {
       return (1 << aType) & mContentBackendBitmask;
     }
 
     virtual bool UseAcceleratedSkiaCanvas();
 
+    virtual void InitializeSkiaCaches();
+
     void GetAzureBackendInfo(mozilla::widget::InfoObject &aObj) {
       aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
       aObj.DefineProperty("AzureSkiaAccelerated", UseAcceleratedSkiaCanvas());
       aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
       aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
     }
 
     mozilla::gfx::BackendType GetPreferredCanvasBackend() {
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -1190,10 +1190,17 @@ StartDiskSpaceWatcher()
 void
 StopDiskSpaceWatcher()
 {
   AssertMainProcess();
   AssertMainThread();
   PROXY_IF_SANDBOXED(StopDiskSpaceWatcher());
 }
 
+uint32_t
+GetTotalSystemMemory()
+{
+  return hal_impl::GetTotalSystemMemory();
+}
+
+
 } // namespace hal
 } // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -592,16 +592,23 @@ void StartDiskSpaceWatcher();
 
 /**
  * Stop monitoring disk space for low space situations.
  *
  * This API is currently only allowed to be used from the main process.
  */
 void StopDiskSpaceWatcher();
 
+/**
+ * Get total system memory of device being run on in bytes.
+ *
+ * Returns 0 if we are unable to determine this information from /proc/meminfo.
+ */
+uint32_t GetTotalSystemMemory();
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #ifdef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_HAL_NAMESPACE
 #endif
 
new file mode 100644
--- /dev/null
+++ b/hal/fallback/FallbackMemory.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Hal.h"
+
+namespace mozilla {
+namespace hal_impl {
+
+uint32_t
+GetTotalSystemMemory()
+{
+	return 0;
+}
+
+} // namespace hal_impl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/hal/linux/LinuxMemory.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include "Hal.h"
+
+namespace mozilla {
+namespace hal_impl {
+
+uint32_t
+GetTotalSystemMemory()
+{
+  static uint32_t sTotalMemory;
+  static bool sTotalMemoryObtained = false;
+
+  if (!sTotalMemoryObtained) {
+    sTotalMemoryObtained = true;
+
+    FILE* fd = fopen("/proc/meminfo", "r");
+    if (!fd) {
+      return 0;
+    }
+
+    int rv = fscanf(fd, "MemTotal: %i kB", &sTotalMemory);
+
+    if (fclose(fd) || rv != 1) {
+      return 0;
+    }
+  }
+
+  return sTotalMemory * 1024;
+}
+
+} // namespace hal_impl
+} // namespace mozilla
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -45,34 +45,37 @@ elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'l
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     CPP_SOURCES += [
         'android/AndroidHal.cpp',
         'android/AndroidSensor.cpp',
         'fallback/FallbackPower.cpp',
         'fallback/FallbackAlarm.cpp',
+        'linux/LinuxMemory.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     CPP_SOURCES += [
         'gonk/GonkDiskSpaceWatcher.cpp',
         'gonk/GonkFMRadio.cpp',
         'gonk/GonkHal.cpp',
         'gonk/GonkSensor.cpp',
         'gonk/GonkSwitch.cpp',
         'gonk/UeventPoller.cpp',
         'linux/LinuxPower.cpp',
+        'linux/LinuxMemory.cpp',
     ]
 elif CONFIG['OS_TARGET'] == 'Linux':
     CPP_SOURCES += [
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackSensor.cpp',
         'fallback/FallbackVibration.cpp',
         'linux/LinuxPower.cpp',
+        'linux/LinuxMemory.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DBUS']:
         CPP_SOURCES += [
             'linux/UPowerClient.cpp',
         ]
     else:
         CPP_SOURCES += [
             'fallback/FallbackBattery.cpp',
@@ -80,32 +83,35 @@ elif CONFIG['OS_TARGET'] == 'Linux':
 elif CONFIG['OS_TARGET'] == 'WINNT':
     CPP_SOURCES += [
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackPower.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackVibration.cpp',
         'windows/WindowsBattery.cpp',
         'windows/WindowsSensor.cpp',
+        'fallback/FallbackMemory.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     CPP_SOURCES += [
         'cocoa/CocoaBattery.cpp',
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackPower.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackVibration.cpp',
+        'fallback/FallbackMemory.cpp',
     ]
 elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
     CPP_SOURCES += [
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackPower.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackSensor.cpp',
         'fallback/FallbackVibration.cpp',
+        'fallback/FallbackMemory.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DBUS']:
         CPP_SOURCES += [
             'linux/UPowerClient.cpp',
         ]
     else:
         CPP_SOURCES += [
             'fallback/FallbackBattery.cpp',
@@ -113,16 +119,17 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 
 else:
     CPP_SOURCES += [
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackBattery.cpp',
         'fallback/FallbackPower.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackSensor.cpp',
         'fallback/FallbackVibration.cpp',
+        'fallback/FallbackMemory.cpp',
     ]
 
 # Fallbacks for backends implemented on Gonk only.
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     CPP_SOURCES += [
         'fallback/FallbackDiskSpaceWatcher.cpp',
         'fallback/FallbackFMRadio.cpp',
         'fallback/FallbackFactoryReset.cpp',