Bug 1105834 - Part 2: Add layers.dump-texture feature. r=mstange
☠☠ backed out by f2bd10f0159c ☠ ☠
authorBenoit Girard <b56girard@gmail.com>
Fri, 28 Nov 2014 17:41:47 -0500
changeset 246277 c3e505887e9fdbd4ceda38eee644f3f028052bea
parent 246276 6aad17f431d1cd199981304464146b29fd75b1ac
child 246278 33592fd41f1f77c7917f7e8bac5c03dd37e26e79
push idunknown
push userunknown
push dateunknown
reviewersmstange
bugs1105834
milestone37.0a1
Bug 1105834 - Part 2: Add layers.dump-texture feature. r=mstange
gfx/layers/LayersLogging.cpp
gfx/layers/composite/CompositableHost.cpp
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/opengl/GrallocTextureHost.cpp
gfx/thebes/gfxPrefs.h
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
modules/libpref/init/all.js
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -322,27 +322,19 @@ AppendToString(std::stringstream& aStrea
 void
 print_stderr(std::stringstream& aStr)
 {
 #if defined(ANDROID)
   // On Android logcat output is truncated to 1024 chars per line, and
   // we usually use std::stringstream to build up giant multi-line gobs
   // of output. So to avoid the truncation we find the newlines and
   // print the lines individually.
-  char line[1024];
-  while (!aStr.eof()) {
-    aStr.getline(line, sizeof(line));
-    if (!aStr.eof() || strlen(line) > 0) {
-      printf_stderr("%s\n", line);
-    }
-    if (aStr.fail()) {
-      // line was too long, skip to next newline
-      aStr.clear();
-      aStr.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
-    }
+  std::string line;
+  while (std::getline(aStr, line)) {
+    printf_stderr("%s\n", line.c_str());
   }
 #else
   printf_stderr("%s", aStr.str().c_str());
 #endif
 }
 
 void
 fprint_stderr(FILE* aFile, std::stringstream& aStr)
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -218,18 +218,17 @@ CompositableHost::DumpTextureHost(std::s
   if (!dSurf) {
     return;
   }
   gfxPlatform *platform = gfxPlatform::GetPlatform();
   RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
                                                                  dSurf->GetSize(),
                                                                  dSurf->Stride(),
                                                                  dSurf->GetFormat());
-  // TODO stream surface
-  gfxUtils::DumpAsDataURI(dt, stderr);
+  aStream << gfxUtils::GetAsDataURI(dt).get();
 }
 #endif
 
 namespace CompositableMap {
 
 typedef std::map<uint64_t, PCompositableParent*> CompositableMap_t;
 static CompositableMap_t* sCompositableMap = nullptr;
 bool IsCreated() {
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -22,16 +22,17 @@
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "mozilla/layers/PTextureParent.h"
 #include "mozilla/unused.h"
 #include <limits>
 #include "SharedSurface.h"
 #include "SharedSurfaceEGL.h"
 #include "SharedSurfaceGL.h"
 #include "../opengl/CompositorOGL.h"
+#include "gfxUtils.h"
 
 #ifdef MOZ_ENABLE_D3D10_LAYER
 #include "../d3d11/CompositorD3D11.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "../opengl/GrallocTextureClient.h"
 #include "../opengl/GrallocTextureHost.h"
@@ -321,16 +322,28 @@ TextureHost::PrintInfo(std::stringstream
   // Note: the TextureHost needs to be locked before it is safe to call
   //       GetSize() and GetFormat() on it.
   if (Lock()) {
     AppendToString(aStream, GetSize(), " [size=", "]");
     AppendToString(aStream, GetFormat(), " [format=", "]");
     Unlock();
   }
   AppendToString(aStream, mFlags, " [flags=", "]");
+#ifdef MOZ_DUMP_PAINTING
+  if (gfxPrefs::LayersDumpTexture()) {
+    nsAutoCString pfx(aPrefix);
+    pfx += "  ";
+
+    aStream << "\n" << pfx.get() << "Surface: ";
+    RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
+    if (dSurf) {
+      aStream << gfxUtils::GetAsDataURI(dSurf).get();
+    }
+  }
+#endif
 }
 
 TextureSource::TextureSource()
 : mCompositableCount(0)
 {
     MOZ_COUNT_CTOR(TextureSource);
 }
 
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -601,40 +601,61 @@ TiledContentHost::RenderLayerBuffer(Tile
 }
 
 void
 TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get();
 
+#ifdef MOZ_DUMP_PAINTING
+  if (gfxPrefs::LayersDumpTexture()) {
+    nsAutoCString pfx(aPrefix);
+    pfx += "  ";
+
+    Dump(aStream, pfx.get(), false);
+  }
+#endif
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 TiledContentHost::Dump(std::stringstream& aStream,
                        const char* aPrefix,
                        bool aDumpHtml)
 {
-  TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin();
-  TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd();
-  if (aDumpHtml) {
-    aStream << "<ul>";
-  }
-  for (;it != stop; ++it) {
-    aStream << aPrefix;
-    aStream << (aDumpHtml ? "<li> <a href=" : "Tile ");
-    if (it->IsPlaceholderTile()) {
-      aStream << "empty tile";
-    } else {
-      DumpTextureHost(aStream, it->mTextureHost);
-      DumpTextureHost(aStream, it->mTextureHostOnWhite);
+  nsIntRect visibleRect = mTiledBuffer.GetValidRegion().GetBounds();
+  gfx::IntSize scaledTileSize = mTiledBuffer.GetScaledTileSize();
+  for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
+    int32_t tileStartX = mTiledBuffer.GetTileStart(x, scaledTileSize.width);
+    int32_t w = scaledTileSize.width - tileStartX;
+    if (x + w > visibleRect.x + visibleRect.width) {
+      w = visibleRect.x + visibleRect.width - x;
     }
-    aStream << (aDumpHtml ? " >Tile</a></li>" : " ");
-  }
-  if (aDumpHtml) {
-    aStream << "</ul>";
+
+    for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
+      int32_t tileStartY = mTiledBuffer.GetTileStart(y, scaledTileSize.height);
+      TileHost tileTexture = mTiledBuffer.
+        GetTile(nsIntPoint(mTiledBuffer.RoundDownToTileEdge(x, scaledTileSize.width),
+                           mTiledBuffer.RoundDownToTileEdge(y, scaledTileSize.height)));
+      int32_t h = scaledTileSize.height - tileStartY;
+      if (y + h > visibleRect.y + visibleRect.height) {
+        h = visibleRect.y + visibleRect.height - y;
+      }
+
+      aStream << "\n" << aPrefix << "Tile (x=" <<
+        mTiledBuffer.RoundDownToTileEdge(x, scaledTileSize.width) << ", y=" <<
+        mTiledBuffer.RoundDownToTileEdge(y, scaledTileSize.height) << "): ";
+      if (tileTexture != mTiledBuffer.GetPlaceholderTile()) {
+        DumpTextureHost(aStream, tileTexture.mTextureHost);
+        // TODO We should combine the OnWhite/OnBlack here an just output a single image.
+      } else {
+        aStream << "empty tile";
+      }
+      y += h;
+    }
+    x += w;
   }
 }
 #endif
 
 } // namespace
 } // namespace
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -3,16 +3,17 @@
  * 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 "base/process.h"
 #include "GLContext.h"
 #include "gfx2DGlue.h"
 #include <ui/GraphicBuffer.h>
 #include "GrallocImages.h"  // for GrallocImage
+#include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/layers/GrallocTextureHost.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "EGLImageHelpers.h"
 #include "GLReadTexImageHelper.h"
 
 namespace mozilla {
 namespace layers {
 
@@ -380,39 +381,55 @@ GrallocTextureHostOGL::GetRenderState()
                             this);
   }
 
   return LayerRenderState();
 }
 
 TemporaryRef<gfx::DataSourceSurface>
 GrallocTextureHostOGL::GetAsSurface() {
-  return mTilingTextureSource ? mTilingTextureSource->GetAsSurface()
-                              : nullptr;
+  if (mTilingTextureSource) {
+    return mTilingTextureSource->GetAsSurface();
+  } else {
+    android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+    uint8_t* grallocData;
+    int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
+    RefPtr<gfx::DataSourceSurface> grallocTempSurf =
+      Factory::CreateWrappingDataSourceSurface(grallocData,
+                                               graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()),
+                                               GetSize(), GetFormat());
+    RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
+
+    graphicBuffer->unlock();
+
+    return surf.forget();
+  }
 }
 
 TemporaryRef<gfx::DataSourceSurface>
 GrallocTextureSourceOGL::GetAsSurface() {
-  if (!IsValid() || !gl()->MakeCurrent()) {
+  if (!IsValid()) {
+    return nullptr;
+  }
+
+  uint8_t* grallocData;
+  int32_t rv = mGraphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
+  if (rv) {
     return nullptr;
   }
 
-  GLuint tex = GetGLTexture();
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-  gl()->fBindTexture(GetTextureTarget(), tex);
-  if (!mEGLImage) {
-    mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
-  }
-  BindEGLImage();
+  RefPtr<gfx::DataSourceSurface> grallocTempSurf =
+    Factory::CreateWrappingDataSourceSurface(grallocData,
+                                             mGraphicBuffer->getStride() * android::bytesPerPixel(mGraphicBuffer->getPixelFormat()),
+                                             GetSize(), GetFormat());
 
-  RefPtr<gfx::DataSourceSurface> surf =
-    IsValid() ? ReadBackSurface(gl(), tex, false, GetFormat())
-              : nullptr;
+  RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
 
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+  mGraphicBuffer->unlock();
+
   return surf.forget();
 }
 
 GLuint
 GrallocTextureSourceOGL::GetGLTexture()
 {
   return mTexture;
 }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -265,16 +265,17 @@ private:
   DECL_GFX_PREF(Once, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, true);
 #endif
   DECL_GFX_PREF(Live, "layers.draw-bigimage-borders",          DrawBigImageBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-borders",                   DrawLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-tile-borders",              DrawTileBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.flash-borders",                  FlashLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-layer-info",                DrawLayerInfo, bool, false);
   DECL_GFX_PREF(Live, "layers.dump",                           LayersDump, bool, false);
+  DECL_GFX_PREF(Live, "layers.dump-texture",                   LayersDumpTexture, bool, false);
 
   // 0 is "no change" for contrast, positive values increase it, negative values
   // decrease it until we hit mid gray at -1 contrast, after that it gets weird.
   DECL_GFX_PREF(Live, "layers.effect.contrast",                LayersEffectContrast, float, 0.0f);
   DECL_GFX_PREF(Live, "layers.effect.grayscale",               LayersEffectGrayscale, bool, false);
   DECL_GFX_PREF(Live, "layers.effect.invert",                  LayersEffectInvert, bool, false);
 
   DECL_GFX_PREF(Once, "layers.enable-tiles",                   LayersTilesEnabledDoNotUseDirectly, bool, false);
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1105,38 +1105,39 @@ gfxUtils::GetColorForFrameNumber(uint64_
         colors[i++] = gfx::Color::FromABGR(0xff999999);
         MOZ_ASSERT(i == sNumFrameColors);
         initialized = true;
     }
 
     return colors[aFrameNumber % sNumFrameColors];
 }
 
-/* static */ nsresult
-gfxUtils::EncodeSourceSurface(SourceSurface* aSurface,
-                              const nsACString& aMimeType,
-                              const nsAString& aOutputOptions,
-                              BinaryOrData aBinaryOrData,
-                              FILE* aFile)
+static nsresult
+EncodeSourceSurfaceInternal(SourceSurface* aSurface,
+                           const nsACString& aMimeType,
+                           const nsAString& aOutputOptions,
+                           gfxUtils::BinaryOrData aBinaryOrData,
+                           FILE* aFile,
+                           nsCString* aStrOut)
 {
-  MOZ_ASSERT(aBinaryOrData == eDataURIEncode || aFile,
+  MOZ_ASSERT(aBinaryOrData == gfxUtils::eDataURIEncode || aFile || aStrOut,
              "Copying binary encoding to clipboard not currently supported");
 
   const IntSize size = aSurface->GetSize();
   if (size.IsEmpty()) {
     return NS_ERROR_INVALID_ARG;
   }
   const Size floatSize(size.width, size.height);
 
   RefPtr<DataSourceSurface> dataSurface;
   if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
     // FIXME bug 995807 (B8G8R8X8), bug 831898 (R5G6B5)
     dataSurface =
-      CopySurfaceToDataSourceSurfaceWithFormat(aSurface,
-                                               SurfaceFormat::B8G8R8A8);
+      gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(aSurface,
+                                                         SurfaceFormat::B8G8R8A8);
   } else {
     dataSurface = aSurface->GetDataSurface();
   }
   if (!dataSurface) {
     return NS_ERROR_FAILURE;
   }
 
   DataSourceSurface::MappedSurface map;
@@ -1209,17 +1210,17 @@ gfxUtils::EncodeSourceSurface(SourceSurf
       if (!imgData.resizeUninitialized(bufSize)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
   }
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(!imgData.empty(), NS_ERROR_FAILURE);
 
-  if (aBinaryOrData == eBinaryEncode) {
+  if (aBinaryOrData == gfxUtils::eBinaryEncode) {
     if (aFile) {
       fwrite(imgData.begin(), 1, imgSize, aFile);
     }
     return NS_OK;
   }
 
   // base 64, result will be null-terminated
   nsCString encodedImg;
@@ -1242,25 +1243,48 @@ gfxUtils::EncodeSourceSurface(SourceSurf
         if (len <= 140)
           break;
         len -= 140;
         cStr += 140;
       }
     }
 #endif
     fprintf(aFile, "%s", string.BeginReading());
+  } else if (aStrOut) {
+    *aStrOut = string;
   } else {
     nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
     if (clipboard) {
       clipboard->CopyString(NS_ConvertASCIItoUTF16(string), nullptr);
     }
   }
   return NS_OK;
 }
 
+static nsCString
+EncodeSourceSurfaceAsPNGURI(SourceSurface* aSurface)
+{
+  nsCString string;
+  EncodeSourceSurfaceInternal(aSurface, NS_LITERAL_CSTRING("image/png"),
+                              EmptyString(), gfxUtils::eDataURIEncode,
+                              nullptr, &string);
+  return string;
+}
+
+/* static */ nsresult
+gfxUtils::EncodeSourceSurface(SourceSurface* aSurface,
+                              const nsACString& aMimeType,
+                              const nsAString& aOutputOptions,
+                              BinaryOrData aBinaryOrData,
+                              FILE* aFile)
+{
+  return EncodeSourceSurfaceInternal(aSurface, aMimeType, aOutputOptions,
+                                     aBinaryOrData, aFile, nullptr);
+}
+
 /* static */ void
 gfxUtils::WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile)
 {
   WriteAsPNG(aSurface, NS_ConvertUTF16toUTF8(aFile).get());
 }
 
 /* static */ void
 gfxUtils::WriteAsPNG(SourceSurface* aSurface, const char* aFile)
@@ -1332,27 +1356,45 @@ gfxUtils::WriteAsPNG(nsIPresShell* aShel
 
 /* static */ void
 gfxUtils::DumpAsDataURI(SourceSurface* aSurface, FILE* aFile)
 {
   EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
                       EmptyString(), eDataURIEncode, aFile);
 }
 
+/* static */ nsCString
+gfxUtils::GetAsDataURI(SourceSurface* aSurface)
+{
+  return EncodeSourceSurfaceAsPNGURI(aSurface);
+}
+
 /* static */ void
 gfxUtils::DumpAsDataURI(DrawTarget* aDT, FILE* aFile)
 {
   RefPtr<SourceSurface> surface = aDT->Snapshot();
   if (surface) {
     DumpAsDataURI(surface, aFile);
   } else {
     NS_WARNING("Failed to get surface!");
   }
 }
 
+/* static */ nsCString
+gfxUtils::GetAsDataURI(DrawTarget* aDT)
+{
+  RefPtr<SourceSurface> surface = aDT->Snapshot();
+  if (surface) {
+    return EncodeSourceSurfaceAsPNGURI(surface);
+  } else {
+    NS_WARNING("Failed to get surface!");
+    return nsCString("");
+  }
+}
+
 /* static */ void
 gfxUtils::CopyAsDataURI(SourceSurface* aSurface)
 {
   EncodeSourceSurface(aSurface, NS_LITERAL_CSTRING("image/png"),
                       EmptyString(), eDataURIEncode, nullptr);
 }
 
 /* static */ void
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -276,16 +276,18 @@ public:
     static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile);
     static inline void DumpAsDataURI(SourceSurface* aSourceSurface) {
         DumpAsDataURI(aSourceSurface, stdout);
     }
     static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile);
     static inline void DumpAsDataURI(DrawTarget* aDT) {
         DumpAsDataURI(aDT, stdout);
     }
+    static nsCString GetAsDataURI(SourceSurface* aSourceSurface);
+    static nsCString GetAsDataURI(DrawTarget* aDT);
 
     /**
      * Copy to the clipboard as a PNG encoded Data URL.
      */
     static void CopyAsDataURI(SourceSurface* aSourceSurface);
     static void CopyAsDataURI(DrawTarget* aDT);
 
 #ifdef MOZ_DUMP_PAINTING
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3888,16 +3888,20 @@ pref("layers.bench.enabled", false);
 pref("layers.acceleration.force-enabled", true);
 #else
 pref("layers.acceleration.force-enabled", false);
 #endif
 
 pref("layers.acceleration.draw-fps", false);
 
 pref("layers.dump", false);
+#ifdef MOZ_DUMP_PAINTING
+// If we're dumping layers, also dump the texture data
+pref("layers.dump-texture", false);
+#endif
 pref("layers.draw-borders", false);
 pref("layers.draw-tile-borders", false);
 pref("layers.draw-bigimage-borders", false);
 pref("layers.frame-counter", false);
 pref("layers.enable-tiles", false);
 pref("layers.tiled-drawtarget.enabled", false);
 pref("layers.low-precision-buffer", false);
 pref("layers.progressive-paint", false);