Bug 1281686 - Part 3: Using MacIOSurface for RectTextureImage. r=mstange
authorMorris Tseng <mtseng@mozilla.com>
Wed, 29 Jun 2016 11:24:44 +0800
changeset 303030 3d40da5e57699583afb009a9978d954e0e034049
parent 303029 a617a11147181e145bd52f97a7616f7fa7371c57
child 303031 e19c4c4eac51da727b0a5e254a3aca0e08e96bac
push id30379
push usercbook@mozilla.com
push dateWed, 29 Jun 2016 14:13:35 +0000
treeherdermozilla-central@b69a5bbb5e40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1281686
milestone50.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 1281686 - Part 3: Using MacIOSurface for RectTextureImage. r=mstange MozReview-Commit-ID: O97FkqrsKq
widget/cocoa/RectTextureImage.h
widget/cocoa/RectTextureImage.mm
widget/cocoa/nsChildView.mm
--- a/widget/cocoa/RectTextureImage.h
+++ b/widget/cocoa/RectTextureImage.h
@@ -21,25 +21,25 @@ namespace widget {
 // Manages a texture which can resize dynamically, binds to the
 // LOCAL_GL_TEXTURE_RECTANGLE_ARB texture target and is automatically backed
 // by a power-of-two size GL texture. The latter two features are used for
 // compatibility with older Mac hardware which we block GL layers on.
 // RectTextureImages are used both for accelerated GL layers drawing and for
 // OMTC BasicLayers drawing.
 class RectTextureImage {
 public:
-  explicit RectTextureImage(gl::GLContext* aGLContext);
+  RectTextureImage();
 
   virtual ~RectTextureImage();
 
   already_AddRefed<gfx::DrawTarget>
     BeginUpdate(const LayoutDeviceIntSize& aNewSize,
                 const LayoutDeviceIntRegion& aDirtyRegion =
                   LayoutDeviceIntRegion());
-  void EndUpdate(bool aKeepSurface = false);
+  void EndUpdate();
 
   void UpdateIfNeeded(const LayoutDeviceIntSize& aNewSize,
                       const LayoutDeviceIntRegion& aDirtyRegion,
                       void (^aCallback)(gfx::DrawTarget*,
                                         const LayoutDeviceIntRegion&))
   {
     RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
     if (drawTarget) {
@@ -56,28 +56,25 @@ public:
     MOZ_ASSERT(mInUpdate, "update region only valid during update");
     return mUpdateRegion;
   }
 
   void Draw(mozilla::layers::GLManager* aManager,
             const LayoutDeviceIntPoint& aLocation,
             const gfx::Matrix4x4& aTransform = gfx::Matrix4x4());
 
-  static LayoutDeviceIntSize TextureSizeForSize(
-    const LayoutDeviceIntSize& aSize);
 
 protected:
+  void DeleteTexture();
+  void BindIOSurfaceToTexture(gl::GLContext* aGL);
 
-  RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
-  UniquePtr<unsigned char[]> mUpdateDrawTargetData;
+  RefPtr<MacIOSurface> mIOSurface;
   gl::GLContext* mGLContext;
   LayoutDeviceIntRegion mUpdateRegion;
-  LayoutDeviceIntSize mUsedSize;
   LayoutDeviceIntSize mBufferSize;
-  LayoutDeviceIntSize mTextureSize;
   GLuint mTexture;
   bool mInUpdate;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // RectTextureImage_h_
--- a/widget/cocoa/RectTextureImage.mm
+++ b/widget/cocoa/RectTextureImage.mm
@@ -2,141 +2,89 @@
 /* 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 "RectTextureImage.h"
 
 #include "gfxUtils.h"
 #include "GLContextCGL.h"
-#include "GLUploadHelpers.h"
 #include "mozilla/layers/GLManager.h"
 #include "mozilla/gfx/MacIOSurface.h"
 #include "OGLShaderProgram.h"
 #include "ScopedGLHelpers.h"
 
 namespace mozilla {
 namespace widget {
 
-RectTextureImage::RectTextureImage(gl::GLContext* aGLContext)
-  : mGLContext(aGLContext)
+RectTextureImage::RectTextureImage()
+  : mGLContext(nullptr)
   , mTexture(0)
   , mInUpdate(false)
 {
 }
 
 RectTextureImage::~RectTextureImage()
 {
-  if (mTexture) {
-    mGLContext->MakeCurrent();
-    mGLContext->fDeleteTextures(1, &mTexture);
-    mTexture = 0;
-  }
-}
-
-LayoutDeviceIntSize
-RectTextureImage::TextureSizeForSize(const LayoutDeviceIntSize& aSize)
-{
-  return LayoutDeviceIntSize(gfx::NextPowerOfTwo(aSize.width),
-                             gfx::NextPowerOfTwo(aSize.height));
+  DeleteTexture();
 }
 
 already_AddRefed<gfx::DrawTarget>
 RectTextureImage::BeginUpdate(const LayoutDeviceIntSize& aNewSize,
                               const LayoutDeviceIntRegion& aDirtyRegion)
 {
   MOZ_ASSERT(!mInUpdate, "Beginning update during update!");
   mUpdateRegion = aDirtyRegion;
-  if (aNewSize != mUsedSize) {
-    mUsedSize = aNewSize;
+  bool needRecreate = false;
+  if (aNewSize != mBufferSize) {
+    mBufferSize = aNewSize;
     mUpdateRegion =
       LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), aNewSize);
+    needRecreate = true;
   }
 
   if (mUpdateRegion.IsEmpty()) {
     return nullptr;
   }
 
-  LayoutDeviceIntSize neededBufferSize = TextureSizeForSize(mUsedSize);
-  if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) {
-    gfx::IntSize size(neededBufferSize.width, neededBufferSize.height);
-    mUpdateDrawTarget = nullptr;
-    mUpdateDrawTargetData = nullptr;
-    gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
-    int32_t stride = size.width * gfx::BytesPerPixel(format);
-    mUpdateDrawTargetData = MakeUnique<unsigned char[]>(stride * size.height);
-    mUpdateDrawTarget =
-      gfx::Factory::CreateDrawTargetForData(gfx::BackendType::SKIA,
-                                            mUpdateDrawTargetData.get(), size,
-                                            stride, format);
-    mBufferSize = neededBufferSize;
+  if (!mIOSurface || needRecreate) {
+    DeleteTexture();
+    mIOSurface = MacIOSurface::CreateIOSurface(mBufferSize.width,
+                                               mBufferSize.height);
   }
 
   mInUpdate = true;
 
-  RefPtr<gfx::DrawTarget> drawTarget = mUpdateDrawTarget;
+  mIOSurface->Lock(false);
+  unsigned char* ioData = (unsigned char*)mIOSurface->GetBaseAddress();
+  gfx::IntSize size(mBufferSize.width, mBufferSize.height);
+  int32_t stride = mIOSurface->GetBytesPerRow();
+  gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
+  RefPtr<gfx::DrawTarget> drawTarget =
+    gfx::Factory::CreateDrawTargetForData(gfx::BackendType::SKIA,
+                                          ioData, size,
+                                          stride, format);
   return drawTarget.forget();
 }
 
-#define NSFoundationVersionWithProperStrideSupportForSubtextureUpload NSFoundationVersionNumber10_6_3
-
-static bool
-CanUploadSubtextures()
-{
-  return NSFoundationVersionNumber >= NSFoundationVersionWithProperStrideSupportForSubtextureUpload;
-}
-
 void
-RectTextureImage::EndUpdate(bool aKeepSurface)
+RectTextureImage::EndUpdate()
 {
   MOZ_ASSERT(mInUpdate, "Ending update while not in update");
-
-  bool needInit = !mTexture;
-  LayoutDeviceIntRegion updateRegion = mUpdateRegion;
-  if (mTextureSize != mBufferSize) {
-    mTextureSize = mBufferSize;
-    needInit = true;
-  }
-
-  if (needInit || !CanUploadSubtextures()) {
-    updateRegion =
-      LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), mTextureSize);
-  }
-
-  gfx::IntPoint srcPoint = updateRegion.GetBounds().TopLeft().ToUnknownPoint();
-  gfx::SurfaceFormat format = mUpdateDrawTarget->GetFormat();
-  int bpp = gfx::BytesPerPixel(format);
-  int32_t stride = mBufferSize.width * bpp;
-  unsigned char* data = mUpdateDrawTargetData.get();
-  data += srcPoint.y * stride + srcPoint.x * bpp;
-
-  UploadImageDataToTexture(mGLContext, data, stride, format,
-                           updateRegion.ToUnknownRegion(), mTexture, nullptr,
-                           needInit, /* aPixelBuffer = */ false,
-                           LOCAL_GL_TEXTURE0,
-                           LOCAL_GL_TEXTURE_RECTANGLE_ARB);
-
-
-
-  if (!aKeepSurface) {
-    mUpdateDrawTarget = nullptr;
-    mUpdateDrawTargetData = nullptr;
-  }
-
+  mIOSurface->Unlock(false);
   mInUpdate = false;
 }
 
 void
 RectTextureImage::UpdateFromCGContext(const LayoutDeviceIntSize& aNewSize,
                                       const LayoutDeviceIntRegion& aDirtyRegion,
                                       CGContextRef aCGContext)
 {
   gfx::IntSize size = gfx::IntSize(CGBitmapContextGetWidth(aCGContext),
                                    CGBitmapContextGetHeight(aCGContext));
-  mBufferSize.SizeTo(size.width, size.height);
   RefPtr<gfx::DrawTarget> dt = BeginUpdate(aNewSize, aDirtyRegion);
   if (dt) {
     gfx::Rect rect(0, 0, size.width, size.height);
     gfxUtils::ClipToRegion(dt, GetUpdateRegion().ToUnknownRegion());
     RefPtr<gfx::SourceSurface> sourceSurface =
       dt->CreateSourceSurfaceFromData(static_cast<uint8_t *>(CGBitmapContextGetData(aCGContext)),
                                       size,
                                       CGBitmapContextGetBytesPerRow(aCGContext),
@@ -149,31 +97,71 @@ RectTextureImage::UpdateFromCGContext(co
   }
 }
 
 void
 RectTextureImage::Draw(layers::GLManager* aManager,
                        const LayoutDeviceIntPoint& aLocation,
                        const gfx::Matrix4x4& aTransform)
 {
-  layers::ShaderProgramOGL* program =
-    aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB, gfx::SurfaceFormat::R8G8B8A8);
+  gl::GLContext* gl = aManager->gl();
+
+  BindIOSurfaceToTexture(gl);
 
-  aManager->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-  aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
+  layers::ShaderProgramOGL* program =
+    aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                         gfx::SurfaceFormat::R8G8B8A8);
+
+  gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl::ScopedBindTexture texture(gl, mTexture, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
 
   aManager->ActivateProgram(program);
   program->SetProjectionMatrix(aManager->GetProjMatrix());
   program->SetLayerTransform(gfx::Matrix4x4(aTransform).PostTranslate(aLocation.x, aLocation.y, 0));
   program->SetTextureTransform(gfx::Matrix4x4());
   program->SetRenderOffset(nsIntPoint(0, 0));
-  program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
+  program->SetTexCoordMultiplier(mBufferSize.width, mBufferSize.height);
   program->SetTextureUnit(0);
 
   aManager->BindAndDrawQuad(program,
-                            gfx::Rect(0.0, 0.0, mUsedSize.width, mUsedSize.height),
+                            gfx::Rect(0.0, 0.0, mBufferSize.width, mBufferSize.height),
                             gfx::Rect(0.0, 0.0, 1.0f, 1.0f));
+}
 
-  aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+void
+RectTextureImage::DeleteTexture()
+{
+  if (mTexture) {
+    MOZ_ASSERT(mGLContext);
+    mGLContext->MakeCurrent();
+    mGLContext->fDeleteTextures(1, &mTexture);
+    mTexture = 0;
+  }
+}
+
+void
+RectTextureImage::BindIOSurfaceToTexture(gl::GLContext* aGL)
+{
+  if (!mTexture) {
+    MOZ_ASSERT(aGL);
+    aGL->fGenTextures(1, &mTexture);
+    aGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+    gl::ScopedBindTexture texture(aGL, mTexture, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                        LOCAL_GL_TEXTURE_MIN_FILTER,
+                        LOCAL_GL_LINEAR);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                        LOCAL_GL_TEXTURE_MAG_FILTER,
+                        LOCAL_GL_LINEAR);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                        LOCAL_GL_TEXTURE_WRAP_T,
+                        LOCAL_GL_CLAMP_TO_EDGE);
+    aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                        LOCAL_GL_TEXTURE_WRAP_S,
+                        LOCAL_GL_CLAMP_TO_EDGE);
+
+    mIOSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(aGL)->GetCGLContext());
+    mGLContext = aGL;
+  }
 }
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -65,16 +65,17 @@
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/BasicCompositor.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "gfxUtils.h"
 #include "gfxPrefs.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/BorrowedContext.h"
+#include "mozilla/gfx/MacIOSurface.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #include "mozilla/a11y/Platform.h"
 #endif
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
@@ -2085,17 +2086,17 @@ void
 nsChildView::MaybeDrawResizeIndicator(GLManager* aManager)
 {
   MutexAutoLock lock(mEffectsLock);
   if (!mShowsResizeIndicator) {
     return;
   }
 
   if (!mResizerImage) {
-    mResizerImage = MakeUnique<RectTextureImage>(aManager->gl());
+    mResizerImage = MakeUnique<RectTextureImage>();
   }
 
   LayoutDeviceIntSize size = mResizeIndicatorRect.Size();
   mResizerImage->UpdateIfNeeded(size, LayoutDeviceIntRegion(), ^(gfx::DrawTarget* drawTarget, const LayoutDeviceIntRegion& updateRegion) {
     ClearRegion(drawTarget, updateRegion);
     gfx::BorrowedCGContext borrow(drawTarget);
     DrawResizer(borrow.cg);
     borrow.Finish();
@@ -2152,31 +2153,37 @@ CreateCGContext(const LayoutDeviceIntSiz
 
   CGContextTranslateCTM(ctx, 0, aSize.height);
   CGContextScaleCTM(ctx, 1, -1);
   CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
 
   return ctx;
 }
 
+LayoutDeviceIntSize
+TextureSizeForSize(const LayoutDeviceIntSize& aSize)
+{
+  return LayoutDeviceIntSize(gfx::NextPowerOfTwo(aSize.width),
+                             gfx::NextPowerOfTwo(aSize.height));
+}
+
 // When this method is entered, mEffectsLock is already being held.
 void
 nsChildView::UpdateTitlebarCGContext()
 {
   if (mTitlebarRect.IsEmpty()) {
     ReleaseTitlebarCGContext();
     return;
   }
 
   NSRect titlebarRect = DevPixelsToCocoaPoints(mTitlebarRect);
   NSRect dirtyRect = [mView convertRect:[(BaseWindow*)[mView window] getAndResetNativeDirtyRect] fromView:nil];
   NSRect dirtyTitlebarRect = NSIntersectionRect(titlebarRect, dirtyRect);
 
-  LayoutDeviceIntSize texSize =
-    RectTextureImage::TextureSizeForSize(mTitlebarRect.Size());
+  LayoutDeviceIntSize texSize = TextureSizeForSize(mTitlebarRect.Size());
   if (!mTitlebarCGContext ||
       CGBitmapContextGetWidth(mTitlebarCGContext) != size_t(texSize.width) ||
       CGBitmapContextGetHeight(mTitlebarCGContext) != size_t(texSize.height)) {
     dirtyTitlebarRect = titlebarRect;
 
     ReleaseTitlebarCGContext();
 
     mTitlebarCGContext = CreateCGContext(texSize);
@@ -2299,17 +2306,17 @@ nsChildView::MaybeDrawTitlebar(GLManager
     return;
   }
 
   LayoutDeviceIntRegion updatedTitlebarRegion;
   updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
   mUpdatedTitlebarRegion.SetEmpty();
 
   if (!mTitlebarImage) {
-    mTitlebarImage = MakeUnique<RectTextureImage>(aManager->gl());
+    mTitlebarImage = MakeUnique<RectTextureImage>();
   }
 
   mTitlebarImage->UpdateFromCGContext(mTitlebarRect.Size(),
                                       updatedTitlebarRegion,
                                       mTitlebarCGContext);
 
   mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft());
 }
@@ -2323,17 +2330,17 @@ DrawTopLeftCornerMask(CGContextRef aCtx,
 
 void
 nsChildView::MaybeDrawRoundedCorners(GLManager* aManager,
                                      const LayoutDeviceIntRect& aRect)
 {
   MutexAutoLock lock(mEffectsLock);
 
   if (!mCornerMaskImage) {
-    mCornerMaskImage = MakeUnique<RectTextureImage>(aManager->gl());
+    mCornerMaskImage = MakeUnique<RectTextureImage>();
   }
 
   LayoutDeviceIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius);
   mCornerMaskImage->UpdateIfNeeded(size, LayoutDeviceIntRegion(), ^(gfx::DrawTarget* drawTarget, const LayoutDeviceIntRegion& updateRegion) {
     ClearRegion(drawTarget, updateRegion);
     RefPtr<gfx::PathBuilder> builder = drawTarget->CreatePathBuilder();
     builder->Arc(gfx::Point(mDevPixelCornerRadius, mDevPixelCornerRadius), mDevPixelCornerRadius, 0, 2.0f * M_PI);
     RefPtr<gfx::Path> path = builder->Finish();
@@ -2650,17 +2657,17 @@ nsChildView::StartRemoteDrawingInRegion(
       return nullptr;
     }
   }
 
   LayoutDeviceIntRegion dirtyRegion(aInvalidRegion);
   LayoutDeviceIntSize renderSize = mBounds.Size();
 
   if (!mBasicCompositorImage) {
-    mBasicCompositorImage = MakeUnique<RectTextureImage>(mGLPresenter->gl());
+    mBasicCompositorImage = MakeUnique<RectTextureImage>();
   }
 
   RefPtr<gfx::DrawTarget> drawTarget =
     mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion);
 
   if (!drawTarget) {
     // Composite unchanged textures.
     DoRemoteComposition(mBounds);
@@ -2671,17 +2678,17 @@ nsChildView::StartRemoteDrawingInRegion(
   *aBufferMode = BufferMode::BUFFER_NONE;
 
   return drawTarget.forget();
 }
 
 void
 nsChildView::EndRemoteDrawing()
 {
-  mBasicCompositorImage->EndUpdate(true);
+  mBasicCompositorImage->EndUpdate();
   DoRemoteComposition(mBounds);
 }
 
 void
 nsChildView::CleanupRemoteDrawing()
 {
   mBasicCompositorImage = nullptr;
   mCornerMaskImage = nullptr;