Bug 818060 - Add a memory reporter for graphics textures. r=BenWa,njn
authorKartikaya Gupta <kgupta@mozilla.com>
Sun, 16 Dec 2012 19:16:26 -0500
changeset 125305 c9d3089866cf1cee0b518b68cb5652cb51f9b2df
parent 125304 e082861f545f96949f4afa0aeaccddd798fd300c
child 125306 3f278fad083bda7d0c438f60d6bb6629398c043b
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa, njn
bugs818060
milestone20.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 818060 - Add a memory reporter for graphics textures. r=BenWa,njn
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextUtils.cpp
gfx/layers/opengl/TiledThebesLayerOGL.cpp
gfx/layers/opengl/TiledThebesLayerOGL.h
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -20,16 +20,18 @@
 
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
 
 #include "mozilla/Preferences.h"
 
 #include "GLTextureImage.h"
 
+#include "nsIMemoryReporter.h"
+
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gl {
 
 #ifdef DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
@@ -83,16 +85,43 @@ static const char *sExtensionNames[] = {
     "GL_ARB_sync",
     "GL_OES_EGL_image",
     "GL_OES_EGL_sync",
     "GL_OES_EGL_image_external",
     "GL_EXT_packed_depth_stencil",
     nullptr
 };
 
+static int64_t sTextureMemoryUsage = 0;
+
+static int64_t
+GetTextureMemoryUsage()
+{
+    return sTextureMemoryUsage;
+}
+
+void
+GLContext::UpdateTextureMemoryUsage(MemoryUse action, GLenum format, GLenum type, uint16_t tileSize)
+{
+    uint32_t bytesPerTexel = mozilla::gl::GetBitsPerTexel(format, type) / 8;
+    int64_t bytes = (int64_t)(tileSize * tileSize * bytesPerTexel);
+    if (action == MemoryFreed) {
+        sTextureMemoryUsage -= bytes;
+    } else {
+        sTextureMemoryUsage += bytes;
+    }
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(TextureMemoryUsage,
+    "gfx-textures",
+    KIND_OTHER,
+    UNITS_BYTES,
+    GetTextureMemoryUsage,
+    "Memory used for storing GL textures.")
+
 /*
  * XXX - we should really know the ARB/EXT variants of these
  * instead of only handling the symbol if it's exposed directly.
  */
 
 bool
 GLContext::InitWithPrefix(const char *prefix, bool trygl)
 {
@@ -639,16 +668,17 @@ GLContext::CanUploadSubTextures()
 
 bool GLContext::sPowerOfTwoForced = false;
 bool GLContext::sPowerOfTwoPrefCached = false;
 
 void
 GLContext::PlatformStartup()
 {
   CacheCanUploadNPOT();
+  NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(TextureMemoryUsage));
 }
 
 void
 GLContext::CacheCanUploadNPOT()
 {
     MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread.");
     MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!");
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2909,16 +2909,30 @@ public:
     nsTArray<NamedResource> mTrackedPrograms;
     nsTArray<NamedResource> mTrackedShaders;
     nsTArray<NamedResource> mTrackedTextures;
     nsTArray<NamedResource> mTrackedFramebuffers;
     nsTArray<NamedResource> mTrackedRenderbuffers;
     nsTArray<NamedResource> mTrackedBuffers;
 #endif
 
+public:
+    enum MemoryUse {
+        // when memory being allocated is reported to a memory reporter
+        MemoryAllocated,
+        // when memory being freed is reported to a memory reporter
+        MemoryFreed
+    };
+
+    // When memory is used/freed for tile textures, call this method
+    // to update the value reported by the memory reporter.
+    static void UpdateTextureMemoryUsage(MemoryUse action,
+                                         GLenum format,
+                                         GLenum type,
+                                         uint16_t tileSize);
 };
 
 inline bool
 DoesStringMatch(const char* aString, const char *aWantedString)
 {
     if (!aString || !aWantedString)
         return false;
 
@@ -3103,12 +3117,14 @@ public:
 
 protected:
     void UnwrapImpl() {
         MOZ_ASSERT(mGL->IsCurrent());
         mGL->BindUserFBO(mOldState);
     }
 };
 
+uint32_t GetBitsPerTexel(GLenum format, GLenum type);
+
 } /* namespace gl */
 } /* namespace mozilla */
 
 #endif /* GLCONTEXT_H_ */
--- a/gfx/gl/GLContextUtils.cpp
+++ b/gfx/gl/GLContextUtils.cpp
@@ -414,11 +414,68 @@ GLContext::BlitTextureToTexture(GLuint s
     // Generally, just use the CopyTexSubImage path
     ScopedFramebufferTexture srcWrapper(this, srcTex);
     MOZ_ASSERT(srcWrapper.IsComplete());
 
     BlitFramebufferToTexture(srcWrapper.FB(), destTex,
                              srcSize, destSize);
 }
 
+uint32_t GetBitsPerTexel(GLenum format, GLenum type)
+{
+    // If there is no defined format or type, we're not taking up any memory
+    if (!format || !type) {
+        return 0;
+    }
+
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        if (type == LOCAL_GL_UNSIGNED_SHORT)
+            return 2;
+        else if (type == LOCAL_GL_UNSIGNED_INT)
+            return 4;
+    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
+            return 4;
+    }
+
+    if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
+        int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
+        switch (format) {
+            case LOCAL_GL_ALPHA:
+            case LOCAL_GL_LUMINANCE:
+                return 1 * multiplier;
+            case LOCAL_GL_LUMINANCE_ALPHA:
+                return 2 * multiplier;
+            case LOCAL_GL_RGB:
+                return 3 * multiplier;
+            case LOCAL_GL_RGBA:
+                return 4 * multiplier;
+            case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+            case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+                return 2;
+            case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+            case LOCAL_GL_ATC_RGB:
+            case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+            case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+                return 4;
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+            case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+            case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+            case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+                return 8;
+            default:
+                break;
+        }
+    } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
+               type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
+               type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
+    {
+        return 16;
+    }
+
+    MOZ_ASSERT(false);
+    return 0;
+}
+
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp
@@ -16,29 +16,29 @@ using mozilla::gl::GLContext;
 
 TiledLayerBufferOGL::~TiledLayerBufferOGL()
 {
   if (mRetainedTiles.Length() == 0)
     return;
 
   mContext->MakeCurrent();
   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
-    if (mRetainedTiles[i] == GetPlaceholderTile())
-      continue;
-    mContext->fDeleteTextures(1, &mRetainedTiles[i].mTextureHandle);
+    ReleaseTile(mRetainedTiles[i]);
   }
 }
 
 void
 TiledLayerBufferOGL::ReleaseTile(TiledTexture aTile)
 {
   // We've made current prior to calling TiledLayerBufferOGL::Update
   if (aTile == GetPlaceholderTile())
     return;
   mContext->fDeleteTextures(1, &aTile.mTextureHandle);
+
+  GLContext::UpdateTextureMemoryUsage(GLContext::MemoryFreed, aTile.mFormat, GetTileType(aTile), GetTileLength());
 }
 
 void
 TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
                             const nsIntRegion& aNewValidRegion,
                             const nsIntRegion& aInvalidateRegion,
                             const gfxSize& aResolution)
 {
@@ -54,16 +54,23 @@ TiledLayerBufferOGL::Upload(const BasicT
   mMainMemoryTiledBuffer = nullptr;
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 10) {
     printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
   }
 #endif
 }
 
+GLenum
+TiledLayerBufferOGL::GetTileType(TiledTexture aTile)
+{
+  // Deduce the type that was assigned in GetFormatAndTileForImageFormat
+  return aTile.mFormat == LOCAL_GL_RGB ? LOCAL_GL_UNSIGNED_SHORT_5_6_5 : LOCAL_GL_UNSIGNED_BYTE;
+}
+
 void
 TiledLayerBufferOGL::GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
                                                     GLenum& aOutFormat,
                                                     GLenum& aOutType)
 {
   if (aFormat == gfxASurface::ImageFormatRGB16_565) {
     aOutFormat = LOCAL_GL_RGB;
     aOutType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
@@ -86,27 +93,32 @@ TiledLayerBufferOGL::ValidateTile(TiledT
     mContext->fGenTextures(1, &aTile.mTextureHandle);
     mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
     mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
     mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
     mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
     mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
   } else {
     mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
+    // We're re-using a texture, but the format may change. Update the memory
+    // reporter with a free and alloc (below) using the old and new formats.
+    GLContext::UpdateTextureMemoryUsage(GLContext::MemoryFreed, aTile.mFormat, GetTileType(aTile), GetTileLength());
   }
 
   nsRefPtr<gfxReusableSurfaceWrapper> reusableSurface = mMainMemoryTiledBuffer->GetTile(aTileOrigin).mSurface.get();
   GLenum format, type;
   GetFormatAndTileForImageFormat(reusableSurface->Format(), format, type);
 
   const unsigned char* buf = reusableSurface->GetReadOnlyData();
   mContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format,
                        GetTileLength(), GetTileLength(), 0,
                        format, type, buf);
 
+  GLContext::UpdateTextureMemoryUsage(GLContext::MemoryAllocated, format, type, GetTileLength());
+
   aTile.mFormat = format;
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   if (PR_IntervalNow() - start > 1) {
     printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
   }
 #endif
   return aTile;
--- a/gfx/layers/opengl/TiledThebesLayerOGL.h
+++ b/gfx/layers/opengl/TiledThebesLayerOGL.h
@@ -95,16 +95,17 @@ protected:
     std::swap(aTileA, aTileB);
   }
 
 private:
   nsRefPtr<gl::GLContext> mContext;
   const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
   gfxSize mFrameResolution;
 
+  GLenum GetTileType(TiledTexture aTile);
   void GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
                                       GLenum& aOutFormat,
                                       GLenum& aOutType);
 };
 
 class TiledThebesLayerOGL : public ShadowThebesLayer,
                             public LayerOGL,
                             public TiledLayerComposer