Bug 920160 - Add prefs for SkiaGL cache size. r=snorp, a=koi+
☠☠ backed out by 7090e4028a66 ☠ ☠
authorGeorge Wright <gwright@mozilla.com>
Tue, 22 Oct 2013 14:15:24 -0500
changeset 160889 382f3133d96188fd237692c537739fc72bc2266c
parent 160888 a7cd08f87a54eda526e16f8f168bc96c23e0a8ea
child 160890 c71d8cd3ddee0d468ab5e721dc951a75dfc1cfbc
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, koi
bugs920160
milestone26.0a2
Bug 920160 - Add prefs for SkiaGL cache size. r=snorp, a=koi+
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
@@ -792,16 +792,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
@@ -975,16 +975,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)
 {
 #ifdef ANDROID
   mSoftClipping = false;
 #else
@@ -735,17 +737,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;
   bool mSoftClipping;
 };
 
--- 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
@@ -60,16 +60,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
 
 #ifdef USE_SKIA_GPU
 #include "skia/GrContext.h"
 #include "skia/GrGLInterface.h"
 #include "GLContextSkia.h"
 #endif
@@ -281,16 +282,20 @@ gfxPlatform::gfxPlatform()
                                  false);
     Preferences::AddBoolVarCache(&mDrawBigImageBorders,
                                  "layers.draw-bigimage-borders",
                                  false);
 
     uint32_t canvasMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA);
     uint32_t contentMask = 0;
     InitBackendPrefs(canvasMask, contentMask);
+
+#ifdef USE_SKIA
+    InitializeSkiaCaches();
+#endif
 }
 
 gfxPlatform*
 gfxPlatform::GetPlatform()
 {
     if (!gPlatform) {
         Init();
     }
@@ -814,16 +819,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
@@ -268,16 +268,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
@@ -1180,10 +1180,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
@@ -585,16 +585,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,29 +45,32 @@ elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'l
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     CPP_SOURCES += [
         'AndroidHal.cpp',
         'AndroidSensor.cpp',
         'FallbackPower.cpp',
         'FallbackAlarm.cpp',
+        'LinuxMemory.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     CPP_SOURCES += [
         'GonkHal.cpp',
+        'LinuxMemory.cpp',
         'LinuxPower.cpp',
         'GonkSensor.cpp',
         'UeventPoller.cpp',
         'GonkSwitch.cpp',
         'GonkFMRadio.cpp',
         'GonkDiskSpaceWatcher.cpp',
     ]
 elif CONFIG['OS_TARGET'] == 'Linux':
     CPP_SOURCES += [
+        'LinuxMemory.cpp',
         'LinuxPower.cpp',
         'FallbackScreenConfiguration.cpp',
         'FallbackSensor.cpp',
         'FallbackVibration.cpp',
         'FallbackAlarm.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DBUS']:
         CPP_SOURCES += [
@@ -79,32 +82,35 @@ elif CONFIG['OS_TARGET'] == 'Linux':
         ]
 elif CONFIG['OS_TARGET'] == 'WINNT':
     CPP_SOURCES += [
         'WindowsBattery.cpp',
         'WindowsSensor.cpp',
         'FallbackVibration.cpp',
         'FallbackScreenConfiguration.cpp',
         'FallbackPower.cpp',
+        'FallbackMemory.cpp',
         'FallbackAlarm.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     CPP_SOURCES += [
         'CocoaBattery.cpp',
         'FallbackVibration.cpp',
         'FallbackPower.cpp',
         'FallbackScreenConfiguration.cpp',
+        'FallbackMemory.cpp',
         'FallbackAlarm.cpp',
     ]
 elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
     CPP_SOURCES += [
         'FallbackSensor.cpp',
         'FallbackVibration.cpp',
         'FallbackPower.cpp',
         'FallbackScreenConfiguration.cpp',
+        'FallbackMemory.cpp',
         'FallbackAlarm.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DBUS']:
         CPP_SOURCES += [
             'UPowerClient.cpp'
         ]
     else:
         CPP_SOURCES += [
@@ -112,16 +118,17 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 
         ]
 else:
     CPP_SOURCES += [
         'FallbackBattery.cpp',
         'FallbackSensor.cpp',
         'FallbackVibration.cpp',
         'FallbackPower.cpp',
         'FallbackScreenConfiguration.cpp',
+        'FallbackMemory.cpp',
         'FallbackAlarm.cpp',
     ]
 
 # Fallbacks for backends implemented on Gonk only.
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     CPP_SOURCES += [
         'FallbackLights.cpp',
         'FallbackTime.cpp',