Bug 1243072 - Make GfxTexturesReporter work again r=nical,jgilbert
authorJames Willcox <snorp@snorp.net>
Tue, 26 Jan 2016 15:03:37 -0600
changeset 282908 de75dce16ee4db1ed112c56a235fa08e719b41d2
parent 282907 ad652aac6b74eb862d79a52b9e516531b51c95df
child 282909 e3ee9f8005b34e564f5bc207c8c0d0f8d7a9500f
push id71356
push userjwillcox@mozilla.com
push dateWed, 03 Feb 2016 20:17:10 +0000
treeherdermozilla-inbound@e3ee9f8005b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical, jgilbert
bugs1243072
milestone47.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 1243072 - Make GfxTexturesReporter work again r=nical,jgilbert
gfx/gl/GLTextureImage.cpp
gfx/gl/GLTextureImage.h
gfx/gl/GLUploadHelpers.cpp
gfx/gl/GLUploadHelpers.h
gfx/gl/GfxTexturesReporter.cpp
gfx/gl/GfxTexturesReporter.h
gfx/gl/TextureImageEGL.cpp
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -7,16 +7,17 @@
 #include "GLContext.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "ScopedGLHelpers.h"
 #include "GLUploadHelpers.h"
+#include "GfxTexturesReporter.h"
 
 #include "TextureImageEGL.h"
 #ifdef XP_MACOSX
 #include "TextureImageCGL.h"
 #endif
 
 using namespace mozilla::gfx;
 
@@ -90,16 +91,26 @@ TextureImage::UpdateFromDataSource(gfx::
 gfx::IntRect TextureImage::GetTileRect() {
     return gfx::IntRect(gfx::IntPoint(0,0), mSize);
 }
 
 gfx::IntRect TextureImage::GetSrcTileRect() {
     return GetTileRect();
 }
 
+void
+TextureImage::UpdateUploadSize(size_t amount)
+{
+    if (mUploadSize > 0) {
+        GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryFreed, mUploadSize);
+    }
+    mUploadSize = amount;
+    GfxTexturesReporter::UpdateAmount(GfxTexturesReporter::MemoryAllocated, mUploadSize);
+}
+
 BasicTextureImage::~BasicTextureImage()
 {
     GLContext *ctx = mGLContext;
     if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
         ctx = ctx->GetSharedContext();
     }
 
     // If we have a context, then we need to delete the texture;
@@ -157,26 +168,30 @@ BasicTextureImage::EndUpdate()
     NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
 
     // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
 
     RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
     RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
 
     bool relative = FinishedSurfaceUpdate();
-
+    size_t uploadSize;
     mTextureFormat =
         UploadSurfaceToTexture(mGLContext,
                                updateData,
                                mUpdateRegion,
                                mTexture,
+                               &uploadSize,
                                mTextureState == Created,
                                mUpdateOffset,
                                relative);
     FinishedSurfaceUpload();
+    if (uploadSize > 0) {
+        UpdateUploadSize(uploadSize);
+    }
 
     mUpdateDrawTarget = nullptr;
     mTextureState = Valid;
 }
 
 void
 BasicTextureImage::BindTexture(GLenum aTextureUnit)
 {
@@ -209,24 +224,29 @@ BasicTextureImage::DirectUpdate(gfx::Dat
     nsIntRegion region;
     if (mTextureState != Valid) {
         bounds = IntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
+    size_t uploadSize;
     mTextureFormat =
         UploadSurfaceToTexture(mGLContext,
                                aSurf,
                                region,
                                mTexture,
+                               &uploadSize,
                                mTextureState == Created,
                                bounds.TopLeft() + IntPoint(aFrom.x, aFrom.y),
                                false);
+    if (uploadSize > 0) {
+        UpdateUploadSize(uploadSize);
+    }
     mTextureState = Valid;
     return true;
 }
 
 void
 BasicTextureImage::Resize(const gfx::IntSize& aSize)
 {
     NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
@@ -268,16 +288,17 @@ TextureImage::TextureImage(const gfx::In
              GLenum aWrapMode, ContentType aContentType,
              Flags aFlags)
     : mSize(aSize)
     , mWrapMode(aWrapMode)
     , mContentType(aContentType)
     , mTextureFormat(gfx::SurfaceFormat::UNKNOWN)
     , mFilter(Filter::GOOD)
     , mFlags(aFlags)
+    , mUploadSize(0)
 {}
 
 BasicTextureImage::BasicTextureImage(GLuint aTexture,
                   const gfx::IntSize& aSize,
                   GLenum aWrapMode,
                   ContentType aContentType,
                   GLContext* aContext,
                   TextureImage::Flags aFlags)
--- a/gfx/gl/GLTextureImage.h
+++ b/gfx/gl/GLTextureImage.h
@@ -198,37 +198,42 @@ public:
     virtual bool InUpdate() const = 0;
     GLenum GetWrapMode() const { return mWrapMode; }
 
     void SetFilter(gfx::Filter aFilter) { mFilter = aFilter; }
 
 protected:
     friend class GLContext;
 
+    void UpdateUploadSize(size_t amount);
+
     /**
      * After the ctor, the TextureImage is invalid.  Implementations
      * must allocate resources successfully before returning the new
      * TextureImage from GLContext::CreateTextureImage().  That is,
      * clients must not be given partially-constructed TextureImages.
      */
     TextureImage(const gfx::IntSize& aSize,
                  GLenum aWrapMode, ContentType aContentType,
                  Flags aFlags = NoFlags);
 
     // Protected destructor, to discourage deletion outside of Release():
-    virtual ~TextureImage() {}
+    virtual ~TextureImage() {
+        UpdateUploadSize(0);
+    }
 
     virtual gfx::IntRect GetSrcTileRect();
 
     gfx::IntSize mSize;
     GLenum mWrapMode;
     ContentType mContentType;
     gfx::SurfaceFormat mTextureFormat;
     gfx::Filter mFilter;
     Flags mFlags;
+    size_t mUploadSize;
 };
 
 /**
  * BasicTextureImage is the baseline TextureImage implementation ---
  * it updates its texture by allocating a scratch buffer for the
  * client to draw into, then using glTexSubImage2D() to upload the new
  * pixels.  Platforms must provide the code to create a new surface
  * into which the updated pixels will be drawn, and the code to
--- a/gfx/gl/GLUploadHelpers.cpp
+++ b/gfx/gl/GLUploadHelpers.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLUploadHelpers.h"
 
 #include "GLContext.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Tools.h"  // For BytesPerPixel
 #include "nsRegion.h"
+#include "GfxTexturesReporter.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace gl {
 
 /* These two techniques are suggested by "Bit Twiddling Hacks"
@@ -374,23 +375,68 @@ TexImage2DHelper(GLContext *gl,
                         format,
                         type,
                         pixels);
         gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
         gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
     }
 }
 
+static uint32_t
+GetBytesPerTexel(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) {
+        uint32_t multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
+        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;
+            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 2;
+    }
+
+    MOZ_RELEASE_ASSERT(false, "Unknown type and/or format");
+    return 0;
+}
+
 SurfaceFormat
 UploadImageDataToTexture(GLContext* gl,
                          unsigned char* aData,
                          int32_t aStride,
                          SurfaceFormat aFormat,
                          const nsIntRegion& aDstRegion,
                          GLuint& aTexture,
+                         size_t* aOutUploadSize,
                          bool aOverwrite,
                          bool aPixelBuffer,
                          GLenum aTextureUnit,
                          GLenum aTextureTarget)
 {
     bool textureInited = aOverwrite ? false : true;
     gl->MakeCurrent();
     gl->fActiveTexture(aTextureUnit);
@@ -500,16 +546,20 @@ UploadImageDataToTexture(GLContext* gl,
         default:
             NS_ASSERTION(false, "Unhandled image surface format!");
     }
 
 
     // Top left point of the region's bounding rectangle.
     IntPoint topLeft = paintRegion.GetBounds().TopLeft();
 
+    if (aOutUploadSize) {
+        *aOutUploadSize = 0;
+    }
+
     for (auto iter = paintRegion.RectIter(); !iter.Done(); iter.Next()) {
         const IntRect& rect = iter.Get();
         // The inital data pointer is at the top left point of the region's
         // bounding rectangle. We need to find the offset of this rect
         // within the region and adjust the data pointer accordingly.
         unsigned char *rectData =
             aData + DataOffset(rect.TopLeft() - topLeft, aStride, aFormat);
 
@@ -539,39 +589,45 @@ UploadImageDataToTexture(GLContext* gl,
                              aStride,
                              pixelSize,
                              0,
                              format,
                              type,
                              rectData);
         }
 
+        if (aOutUploadSize && !textureInited) {
+            uint32_t texelSize = GetBytesPerTexel(internalFormat, type);
+            size_t numTexels = size_t(rect.width) * size_t(rect.height);
+            *aOutUploadSize += texelSize * numTexels;
+        }
     }
 
     return surfaceFormat;
 }
 
 SurfaceFormat
 UploadSurfaceToTexture(GLContext* gl,
-                       DataSourceSurface *aSurface,
+                       DataSourceSurface* aSurface,
                        const nsIntRegion& aDstRegion,
                        GLuint& aTexture,
+                       size_t* aOutUploadSize,
                        bool aOverwrite,
                        const gfx::IntPoint& aSrcPoint,
                        bool aPixelBuffer,
                        GLenum aTextureUnit,
                        GLenum aTextureTarget)
 {
     unsigned char* data = aPixelBuffer ? nullptr : aSurface->GetData();
     int32_t stride = aSurface->Stride();
     SurfaceFormat format = aSurface->GetFormat();
     data += DataOffset(aSrcPoint, stride, format);
     return UploadImageDataToTexture(gl, data, stride, format,
-                                    aDstRegion, aTexture, aOverwrite,
-                                    aPixelBuffer, aTextureUnit,
+                                    aDstRegion, aTexture, aOutUploadSize,
+                                    aOverwrite, aPixelBuffer, aTextureUnit,
                                     aTextureTarget);
 }
 
 bool
 CanUploadNonPowerOfTwo(GLContext* gl)
 {
     if (!gl->WorkAroundDriverBugs())
         return true;
--- a/gfx/gl/GLUploadHelpers.h
+++ b/gfx/gl/GLUploadHelpers.h
@@ -35,16 +35,17 @@ class GLContext;
   * texture memory block allocated.
   *
   * The aDstPoint parameter is ignored if no texture was provided
   * or aOverwrite is true.
   *
   * \param aData Image data to upload.
   * \param aDstRegion Region of texture to upload to.
   * \param aTexture Texture to use, or 0 to have one created for you.
+  * \param aOutUploadSize if set, the number of bytes the texture requires will be returned here
   * \param aOverwrite Over an existing texture with a new one.
   * \param aSrcPoint Offset into aSrc where the region's bound's
   *  TopLeft() sits.
   * \param aPixelBuffer Pass true to upload texture data with an
   *  offset from the base data (generally for pixel buffer objects),
   *  otherwise textures are upload with an absolute pointer to the data.
   * \param aTextureUnit, the texture unit used temporarily to upload the
   *  surface. This testure may be overridden, clients should not rely on
@@ -54,29 +55,31 @@ class GLContext;
   */
 gfx::SurfaceFormat
 UploadImageDataToTexture(GLContext* gl,
                          unsigned char* aData,
                          int32_t aStride,
                          gfx::SurfaceFormat aFormat,
                          const nsIntRegion& aDstRegion,
                          GLuint& aTexture,
+                         size_t* aOutUploadSize = nullptr,
                          bool aOverwrite = false,
                          bool aPixelBuffer = false,
                          GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
                          GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
 
 /**
   * Convenience wrapper around UploadImageDataToTexture for gfx::DataSourceSurface's.
   */
 gfx::SurfaceFormat
 UploadSurfaceToTexture(GLContext* gl,
                        gfx::DataSourceSurface *aSurface,
                        const nsIntRegion& aDstRegion,
                        GLuint& aTexture,
+                       size_t* aOutUploadSize = nullptr,
                        bool aOverwrite = false,
                        const gfx::IntPoint& aSrcPoint = gfx::IntPoint(0, 0),
                        bool aPixelBuffer = false,
                        GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
                        GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
 
 bool CanUploadSubTextures(GLContext* gl);
 bool CanUploadNonPowerOfTwo(GLContext* gl);
--- a/gfx/gl/GfxTexturesReporter.cpp
+++ b/gfx/gl/GfxTexturesReporter.cpp
@@ -1,99 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
 /* 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 "GfxTexturesReporter.h"
-#include "GLDefs.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
 
 NS_IMPL_ISUPPORTS(GfxTexturesReporter, nsIMemoryReporter)
 
-Atomic<int32_t> GfxTexturesReporter::sAmount(0);
-Atomic<int32_t> GfxTexturesReporter::sTileWasteAmount(0);
-
-static 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*8;
-        else if (type == LOCAL_GL_UNSIGNED_INT)
-            return 4*8;
-    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
-        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
-            return 4*8;
-    }
-
-    if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
-        uint32_t 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:
-            case LOCAL_GL_ETC1_RGB8_OES:
-            case LOCAL_GL_COMPRESSED_RGB8_ETC2:
-            case LOCAL_GL_COMPRESSED_SRGB8_ETC2:
-            case LOCAL_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-            case LOCAL_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-            case LOCAL_GL_COMPRESSED_R11_EAC:
-            case LOCAL_GL_COMPRESSED_SIGNED_R11_EAC:
-                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:
-            case LOCAL_GL_COMPRESSED_RGBA8_ETC2_EAC:
-            case LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-            case LOCAL_GL_COMPRESSED_RG11_EAC:
-            case LOCAL_GL_COMPRESSED_SIGNED_RG11_EAC:
-                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 2*8;
-    }
-
-    MOZ_ASSERT(false);
-    return 0;
-}
+Atomic<size_t> GfxTexturesReporter::sAmount(0);
+Atomic<size_t> GfxTexturesReporter::sTileWasteAmount(0);
 
 /* static */ void
-GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
-                                  GLenum type, int32_t tileWidth,
-                                  int32_t tileHeight)
+GfxTexturesReporter::UpdateAmount(MemoryUse action, size_t amount)
 {
-    int64_t bitsPerTexel = GetBitsPerTexel(format, type);
-    int64_t bytes = int64_t(tileWidth) * int64_t(tileHeight) * bitsPerTexel/8;
     if (action == MemoryFreed) {
-        sAmount -= bytes;
+        MOZ_RELEASE_ASSERT(amount <= sAmount);
+        sAmount -= amount;
     } else {
-        sAmount += bytes;
+        sAmount += amount;
     }
 }
--- a/gfx/gl/GfxTexturesReporter.h
+++ b/gfx/gl/GfxTexturesReporter.h
@@ -36,38 +36,37 @@ public:
         // 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 this memory reporter.
-    static void UpdateAmount(MemoryUse action, GLenum format, GLenum type,
-                             int32_t tileWidth, int32_t tileHeight);
+    static void UpdateAmount(MemoryUse action, size_t amount);
 
-    static void UpdateWasteAmount(int32_t delta) {
+    static void UpdateWasteAmount(size_t delta) {
       sTileWasteAmount += delta;
     }
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                               nsISupports* aData, bool aAnonymize) override
     {
         MOZ_COLLECT_REPORT("gfx-tiles-waste", KIND_OTHER, UNITS_BYTES,
-            sTileWasteAmount,
+            int64_t(sTileWasteAmount),
             "Memory lost due to tiles extending past content boundaries");
         return MOZ_COLLECT_REPORT(
-            "gfx-textures", KIND_OTHER, UNITS_BYTES, sAmount,
+            "gfx-textures", KIND_OTHER, UNITS_BYTES, int64_t(sAmount),
             "Memory used for storing GL textures.");
     }
 
 private:
-    static Atomic<int32_t> sAmount;
+    static Atomic<size_t> sAmount;
     // Count the amount of memory lost to tile waste
-    static Atomic<int32_t> sTileWasteAmount;
+    static Atomic<size_t> sTileWasteAmount;
 };
 
 class GfxTextureWasteTracker {
 public:
   GfxTextureWasteTracker()
     : mBytes(0)
   {
     MOZ_COUNT_CTOR(GfxTextureWasteTracker);
--- a/gfx/gl/TextureImageEGL.cpp
+++ b/gfx/gl/TextureImageEGL.cpp
@@ -202,24 +202,29 @@ TextureImageEGL::DirectUpdate(gfx::DataS
     nsIntRegion region;
     if (mTextureState != Valid) {
         bounds = gfx::IntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
+    size_t uploadSize = 0;
     mTextureFormat =
       UploadSurfaceToTexture(mGLContext,
                              aSurf,
                              region,
                              mTexture,
+                             &uploadSize,
                              mTextureState == Created,
                              bounds.TopLeft() + gfx::IntPoint(aFrom.x, aFrom.y),
                              false);
+    if (uploadSize > 0) {
+        UpdateUploadSize(uploadSize);
+    }
 
     mTextureState = Valid;
     return true;
 }
 
 void
 TextureImageEGL::BindTexture(GLenum aTextureUnit)
 {