Bug 747811 - Add gfxReusableImageSurfaceWrapper. r=BenWa
authorChris Lord <chrislord.net@gmail.com>
Mon, 19 Aug 2013 14:59:27 +0100
changeset 143123 2e1710495bd9f31109899d08e8353da809c249a6
parent 143122 97d2a33c5455ee88788ea2bf4802a9edc4d63282
child 143124 18fbb6afc9d42faaca1727dde54c19d00717ce48
push idunknown
push userunknown
push dateunknown
reviewersBenWa
bugs747811
milestone26.0a1
Bug 747811 - Add gfxReusableImageSurfaceWrapper. r=BenWa Add an implementation of gfxReusableSurfaceWrapper based on gfxImageSurface and use it on Android to avoid the overhead of shared memory.
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/client/TiledContentClient.h
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/thebes/gfxReusableImageSurfaceWrapper.cpp
gfx/thebes/gfxReusableImageSurfaceWrapper.h
gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
gfx/thebes/gfxReusableSurfaceWrapper.h
gfx/thebes/moz.build
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -9,22 +9,28 @@
 #include "mozilla/layers/ImageClient.h"
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "GLContext.h"
 #include "BasicLayers.h" // for PaintContext
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
-#include "gfxReusableSharedImageSurfaceWrapper.h"
-#include "gfxSharedImageSurface.h"
 #include "gfxPlatform.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "gfx2DGlue.h"
 
+#ifdef MOZ_ANDROID_OMTC
+#  include "gfxReusableImageSurfaceWrapper.h"
+#  include "gfxImageSurface.h"
+#else
+#  include "gfxReusableSharedImageSurfaceWrapper.h"
+#  include "gfxSharedImageSurface.h"
+#endif
+
 #include <stdint.h>
 
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 TextureClient::TextureClient(TextureFlags aFlags)
@@ -471,21 +477,31 @@ DeprecatedTextureClientTile::DeprecatedT
   mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED;
 }
 
 bool
 DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gfxContentType aType)
 {
   if (!mSurface ||
       mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) {
+#ifdef MOZ_ANDROID_OMTC
+    // If we're using OMTC, we can save some cycles by not using shared
+    // memory. Using shared memory here is a small, but significant
+    // performance regression.
+    gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height),
+                                                   gfxPlatform::GetPlatform()->OptimalFormatForContent(aType),
+                                                   aType != gfxASurface::CONTENT_COLOR);
+    mSurface = new gfxReusableImageSurfaceWrapper(tmpTile);
+#else
     nsRefPtr<gfxSharedImageSurface> sharedImage =
       gfxSharedImageSurface::CreateUnsafe(mForwarder,
                                           gfxIntSize(aSize.width, aSize.height),
                                           gfxPlatform::GetPlatform()->OptimalFormatForContent(aType));
     mSurface = new gfxReusableSharedImageSurfaceWrapper(mForwarder, sharedImage);
+#endif
     mContentType = aType;
   }
   return true;
 }
 
 gfxImageSurface*
 DeprecatedTextureClientTile::LockImageSurface()
 {
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -75,17 +75,17 @@ void
 TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
 {
   BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
     ? &mLowPrecisionTiledBuffer
     : &mTiledBuffer;
 
   // Take an extra ReadLock on behalf of the TiledContentHost. This extra
   // reference will be adopted when the descriptor is opened by
-  // gfxReusableSharedImageSurfaceWrapper::Open.
+  // BasicTiledLayerTile::OpenDescriptor.
   buffer->ReadLock();
 
   mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
   buffer->ClearPaintedRegion();
 }
 
 BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
                                              ClientLayerManager* aManager)
@@ -108,29 +108,59 @@ BasicTiledLayerBuffer::GetContentType() 
   if (mThebesLayer->CanUseOpaqueSurface()) {
     return gfxASurface::CONTENT_COLOR;
   } else {
     return gfxASurface::CONTENT_COLOR_ALPHA;
   }
 }
 
 
-BasicTileDescriptor
+TileDescriptor
 BasicTiledLayerTile::GetTileDescriptor()
 {
-  return BasicTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(GetSurface())->GetShmem());
+  gfxReusableSurfaceWrapper* surface = GetSurface();
+  switch (surface->GetType()) {
+  case gfxReusableSurfaceWrapper::TYPE_IMAGE :
+    return BasicTileDescriptor(uintptr_t(surface));
+
+  case gfxReusableSurfaceWrapper::TYPE_SHARED_IMAGE :
+    return BasicShmTileDescriptor(static_cast<gfxReusableSharedImageSurfaceWrapper*>(surface)->GetShmem());
+
+  default :
+    NS_NOTREACHED("Unhandled gfxReusableSurfaceWrapper type");
+    return PlaceholderTileDescriptor();
+  }
 }
 
+
 /* static */ BasicTiledLayerTile
-BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc)
+BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc)
 {
-  nsRefPtr<gfxReusableSurfaceWrapper> surface =
-    gfxReusableSharedImageSurfaceWrapper::Open(aAllocator, aDesc.reusableSurface());
-  return BasicTiledLayerTile(
-    new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+  switch (aDesc.type()) {
+  case TileDescriptor::TBasicShmTileDescriptor : {
+    nsRefPtr<gfxReusableSurfaceWrapper> surface =
+      gfxReusableSharedImageSurfaceWrapper::Open(
+        aAllocator, aDesc.get_BasicShmTileDescriptor().reusableSurface());
+    return BasicTiledLayerTile(
+      new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+  }
+
+  case TileDescriptor::TBasicTileDescriptor : {
+    nsRefPtr<gfxReusableSurfaceWrapper> surface =
+      reinterpret_cast<gfxReusableSurfaceWrapper*>(
+        aDesc.get_BasicTileDescriptor().reusableSurface());
+    surface->ReadUnlock();
+    return BasicTiledLayerTile(
+      new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
+  }
+
+  default :
+    NS_NOTREACHED("Unknown tile descriptor type!");
+    return nullptr;
+  }
 }
 
 SurfaceDescriptorTiles
 BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
 {
   InfallibleTArray<TileDescriptor> tiles;
 
   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -65,18 +65,18 @@ struct BasicTiledLayerTile {
 
   void ReadUnlock() {
     GetSurface()->ReadUnlock();
   }
   void ReadLock() {
     GetSurface()->ReadLock();
   }
 
-  BasicTileDescriptor GetTileDescriptor();
-  static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc);
+  TileDescriptor GetTileDescriptor();
+  static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const TileDescriptor& aDesc);
 
   gfxReusableSurfaceWrapper* GetSurface() {
     return mDeprecatedTextureClient->GetReusableSurfaceWrapper();
   }
 };
 
 /**
  * This struct stores all the data necessary to perform a paint so that it
@@ -130,18 +130,17 @@ public:
     mRetainedWidth = aRetainedWidth;
     mRetainedHeight = aRetainedHeight;
     mResolution = aResolution;
 
     for(size_t i = 0; i < aTiles.Length(); i++) {
       if (aTiles[i].type() == TileDescriptor::TPlaceholderTileDescriptor) {
         mRetainedTiles.AppendElement(GetPlaceholderTile());
       } else {
-        const BasicTileDescriptor& basicTileDesc = aTiles[i].get_BasicTileDescriptor();
-        mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, basicTileDesc));
+        mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, aTiles[i]));
       }
     }
   }
 
   void PaintThebes(const nsIntRegion& aNewValidRegion,
                    const nsIntRegion& aPaintRegion,
                    LayerManager::DrawThebesLayerCallback aCallback,
                    void* aCallbackData);
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -48,25 +48,30 @@ struct SurfaceDescriptorD3D10 {
 
 struct SharedTextureDescriptor {
   SharedTextureShareType shareType;
   SharedTextureHandle handle;
   nsIntSize size;
   bool inverted;
 };
 
+struct BasicShmTileDescriptor {
+  Shmem reusableSurface;
+};
+
 struct BasicTileDescriptor {
-  Shmem reusableSurface;
+  uintptr_t reusableSurface;
 };
 
 struct PlaceholderTileDescriptor {
 };
 
 union TileDescriptor {
   BasicTileDescriptor;
+  BasicShmTileDescriptor;
   PlaceholderTileDescriptor;
 };
 
 struct SurfaceDescriptorTiles {
   nsIntRegion validRegion;
   nsIntRegion paintedRegion;
   TileDescriptor[] tiles;
   int         retainedWidth;
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxReusableImageSurfaceWrapper.cpp
@@ -0,0 +1,61 @@
+/* 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 "gfxReusableImageSurfaceWrapper.h"
+#include "gfxImageSurface.h"
+
+gfxReusableImageSurfaceWrapper::gfxReusableImageSurfaceWrapper(gfxImageSurface* aSurface)
+  : mSurface(aSurface)
+{
+  MOZ_COUNT_CTOR(gfxReusableImageSurfaceWrapper);
+}
+
+gfxReusableImageSurfaceWrapper::~gfxReusableImageSurfaceWrapper()
+{
+  MOZ_COUNT_DTOR(gfxReusableImageSurfaceWrapper);
+}
+
+void
+gfxReusableImageSurfaceWrapper::ReadLock()
+{
+  NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadLock");
+  AddRef();
+}
+
+void
+gfxReusableImageSurfaceWrapper::ReadUnlock()
+{
+  Release();
+}
+
+gfxReusableSurfaceWrapper*
+gfxReusableImageSurfaceWrapper::GetWritable(gfxImageSurface** aSurface)
+{
+  NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call GetWritable");
+
+  if (mRefCnt == 1) {
+    *aSurface = mSurface;
+    return this;
+  }
+
+  // Something else is reading the surface, copy it
+  gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format(), false);
+  copySurface->CopyFrom(mSurface);
+  *aSurface = copySurface;
+
+  return new gfxReusableImageSurfaceWrapper(copySurface);
+}
+
+const unsigned char*
+gfxReusableImageSurfaceWrapper::GetReadOnlyData() const
+{
+  return mSurface->Data();
+}
+
+gfxASurface::gfxImageFormat
+gfxReusableImageSurfaceWrapper::Format()
+{
+  return mSurface->Format();
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxReusableImageSurfaceWrapper.h
@@ -0,0 +1,36 @@
+/* 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/. */
+
+#ifndef GFXMEMCOWSURFACEWRAPPER
+#define GFXMEMCOWSURFACEWRAPPER
+
+#include "gfxReusableSurfaceWrapper.h"
+
+class gfxImageSurface;
+
+/**
+ * A cross-thread capable implementation of gfxReusableSurfaceWrapper based
+ * on gfxImageSurface.
+ */
+class gfxReusableImageSurfaceWrapper : public gfxReusableSurfaceWrapper {
+public:
+  gfxReusableImageSurfaceWrapper(gfxImageSurface* aSurface);
+  ~gfxReusableImageSurfaceWrapper();
+
+  const unsigned char* GetReadOnlyData() const MOZ_OVERRIDE;
+  gfxASurface::gfxImageFormat Format() MOZ_OVERRIDE;
+  gfxReusableSurfaceWrapper* GetWritable(gfxImageSurface** aSurface) MOZ_OVERRIDE;
+  void ReadLock() MOZ_OVERRIDE;
+  void ReadUnlock() MOZ_OVERRIDE;
+
+  Type GetType()
+  {
+    return TYPE_IMAGE;
+  }
+
+private:
+  nsRefPtr<gfxImageSurface>         mSurface;
+};
+
+#endif // GFXMEMCOWSURFACEWRAPPER
--- a/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
+++ b/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
@@ -21,16 +21,21 @@ public:
   ~gfxReusableSharedImageSurfaceWrapper();
 
   const unsigned char* GetReadOnlyData() const MOZ_OVERRIDE;
   gfxASurface::gfxImageFormat Format() MOZ_OVERRIDE;
   gfxReusableSurfaceWrapper* GetWritable(gfxImageSurface** aSurface) MOZ_OVERRIDE;
   void ReadLock() MOZ_OVERRIDE;
   void ReadUnlock() MOZ_OVERRIDE;
 
+  Type GetType()
+  {
+    return TYPE_SHARED_IMAGE;
+  }
+
   /**
    * Returns the shared memory segment that backs the shared image surface.
    */
   mozilla::ipc::Shmem& GetShmem();
 
   /**
    * Create a gfxReusableSurfaceWrapper from the shared memory segment of a
    * gfxSharedImageSurface. A ReadLock must be held, which will be adopted by
--- a/gfx/thebes/gfxReusableSurfaceWrapper.h
+++ b/gfx/thebes/gfxReusableSurfaceWrapper.h
@@ -60,13 +60,28 @@ public:
    *
    * When a surface's read count falls to zero, its memory will be
    * deallocated. It is the responsibility of the user to make sure
    * that all locks are matched with an equal number of unlocks.
    */
   virtual void ReadLock() = 0;
   virtual void ReadUnlock() = 0;
 
+  /**
+   * Types for each implementation of gfxReusableSurfaceWrapper.
+   */
+  enum Type {
+    TYPE_SHARED_IMAGE,
+    TYPE_IMAGE,
+
+    TYPE_MAX
+  };
+
+  /**
+   * Returns a unique ID for each implementation of gfxReusableSurfaceWrapper.
+   */
+  virtual Type GetType() = 0;
+
 protected:
   NS_DECL_OWNINGTHREAD
 };
 
 #endif // GFXCOWSURFACEWRAPPER
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -31,16 +31,17 @@ EXPORTS += [
     'gfxPattern.h',
     'gfxPlatform.h',
     'gfxPoint.h',
     'gfxPoint3D.h',
     'gfxPointH3D.h',
     'gfxQuad.h',
     'gfxQuaternion.h',
     'gfxRect.h',
+    'gfxReusableImageSurfaceWrapper.h',
     'gfxReusableSharedImageSurfaceWrapper.h',
     'gfxReusableSurfaceWrapper.h',
     'gfxSVGGlyphs.h',
     'gfxSharedImageSurface.h',
     'gfxSharedQuartzSurface.h',
     'gfxSkipChars.h',
     'gfxTeeSurface.h',
     'gfxTypes.h',
@@ -246,16 +247,17 @@ CPP_SOURCES += [
     'gfxHarfBuzzShaper.cpp',
     'gfxImageSurface.cpp',
     'gfxMatrix.cpp',
     'gfxPath.cpp',
     'gfxPattern.cpp',
     'gfxPlatform.cpp',
     'gfxPlatformFontList.cpp',
     'gfxRect.cpp',
+    'gfxReusableImageSurfaceWrapper.cpp',
     'gfxReusableSharedImageSurfaceWrapper.cpp',
     'gfxSVGGlyphs.cpp',
     'gfxScriptItemizer.cpp',
     'gfxSkipChars.cpp',
     'gfxTeeSurface.cpp',
     'gfxUserFontSet.cpp',
     'gfxUtils.cpp',
     'nsSurfaceTexture.cpp',