Bug 1335895 - part 14: Update LayerManagerComposite render static toolbar snapshot and handle robocop screen captures r=kats,botond draft
authorRandall Barker <rbarker@mozilla.com>
Mon, 27 Mar 2017 10:40:23 -0700
changeset 561580 0b6a0bc5ffd29dce14469e118f74ef9825c69bb7
parent 561579 1aa6ceb0ccf7a04ec79fe18000ff750e903803e4
child 561581 1e63fda025918fa634252534485d56c3579502e8
push id53787
push userbmo:rbarker@mozilla.com
push dateWed, 12 Apr 2017 22:56:58 +0000
reviewerskats, botond
bugs1335895
milestone55.0a1
Bug 1335895 - part 14: Update LayerManagerComposite render static toolbar snapshot and handle robocop screen captures r=kats,botond
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -48,24 +48,25 @@
 #include "nsAppRunner.h"
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING, NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion, etc
-#ifdef MOZ_WIDGET_ANDROID
+#if defined(MOZ_WIDGET_ANDROID)
 #include <android/log.h>
 #include <android/native_window.h>
-#endif
-#if defined(MOZ_WIDGET_ANDROID)
+#include "mozilla/widget/AndroidCompositorWidget.h"
 #include "opengl/CompositorOGL.h"
+#include "GLConsts.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
+#include "mozilla/Unused.h"
 #include "mozilla/widget/AndroidCompositorWidget.h"
 #include "ScopedGLHelpers.h"
 #endif
 #include "GeckoProfiler.h"
 #include "TextRenderer.h"               // for TextRenderer
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "TreeTraversal.h"              // for ForEachNode
 
@@ -142,16 +143,19 @@ HostLayerManager::RecordUpdateTime(float
  */
 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
 : mUnusedApzTransformWarning(false)
 , mDisabledApzWarning(false)
 , mCompositor(aCompositor)
 , mInTransaction(false)
 , mIsCompositorReady(false)
 , mGeometryChanged(true)
+#if defined(MOZ_WIDGET_ANDROID)
+, mScreenPixelsTarget(nullptr)
+#endif // defined(MOZ_WIDGET_ANDROID)
 {
   mTextRenderer = new TextRenderer();
   mDiagnostics = MakeUnique<Diagnostics>();
   MOZ_ASSERT(aCompositor);
 
 #ifdef USE_SKIA
   mPaintCounter = nullptr;
 #endif
@@ -833,16 +837,35 @@ ClearLayerFlags(Layer* aLayer) {
       [] (Layer* layer)
       {
         if (layer->AsHostLayer()) {
           static_cast<LayerComposite*>(layer->AsHostLayer())->SetLayerComposited(false);
         }
       });
 }
 
+#if defined(MOZ_WIDGET_ANDROID)
+class ScopedCompositorRenderOffset {
+public:
+  ScopedCompositorRenderOffset(CompositorOGL* aCompositor, const ScreenPoint& aOffset) :
+    mCompositor(aCompositor),
+    mOriginalOffset(mCompositor->GetScreenRenderOffset())
+  {
+    mCompositor->SetScreenRenderOffset(aOffset);
+  }
+  ~ScopedCompositorRenderOffset()
+  {
+    mCompositor->SetScreenRenderOffset(mOriginalOffset);
+  }
+private:
+  CompositorOGL* const mCompositor;
+  const ScreenPoint mOriginalOffset;
+};
+#endif // defined(MOZ_WIDGET_ANDROID)
+
 void
 LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion)
 {
   PROFILER_LABEL("LayerManagerComposite", "Render",
     js::ProfileEntry::Category::GRAPHICS);
 
   if (mDestroyed || !mCompositor || mCompositor->IsDestroyed()) {
     NS_WARNING("Call on destroyed layer manager");
@@ -918,16 +941,21 @@ LayerManagerComposite::Render(const nsIn
     clipRect = *mRoot->GetClipRect();
     IntRect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
     mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds);
   } else {
     gfx::IntRect rect;
     mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion, &rect, &actualBounds);
     clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
   }
+#if defined(MOZ_WIDGET_ANDROID)
+  int32_t toolbarHeight = RenderToolbar();
+  // This doesn't affect the projection matrix after BeginFrame has been called.
+  ScopedCompositorRenderOffset scopedOffset(mCompositor->AsCompositorOGL(), ScreenPoint(0, toolbarHeight));
+#endif
 
   if (actualBounds.IsEmpty()) {
     mCompositor->GetWidget()->PostRender(&widgetContext);
     return;
   }
 
   // Allow widget to render a custom background.
   mCompositor->GetWidget()->DrawWindowUnderlay(
@@ -971,16 +999,20 @@ LayerManagerComposite::Render(const nsIn
                             grayscaleVal, invertVal, contrastVal);
   }
 
   // Allow widget to render a custom foreground.
   mCompositor->GetWidget()->DrawWindowOverlay(
     &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
 
   mCompositor->NormalDrawingDone();
+    
+#if defined(MOZ_WIDGET_ANDROID)
+  HandlePixelsTarget();
+#endif // defined(MOZ_WIDGET_ANDROID)
 
   // Debugging
   RenderDebugOverlay(actualBounds);
 
   {
     PROFILER_LABEL("LayerManagerComposite", "EndFrame",
       js::ProfileEntry::Category::GRAPHICS);
 
@@ -1026,33 +1058,16 @@ public:
   {
     mCompositor->SetDestinationSurfaceSize(mOriginalSize);
   }
 private:
   CompositorOGL* const mCompositor;
   const gfx::IntSize mOriginalSize;
 };
 
-class ScopedCompositorRenderOffset {
-public:
-  ScopedCompositorRenderOffset(CompositorOGL* aCompositor, const ScreenPoint& aOffset) :
-    mCompositor(aCompositor),
-    mOriginalOffset(mCompositor->GetScreenRenderOffset())
-  {
-    mCompositor->SetScreenRenderOffset(aOffset);
-  }
-  ~ScopedCompositorRenderOffset()
-  {
-    mCompositor->SetScreenRenderOffset(mOriginalOffset);
-  }
-private:
-  CompositorOGL* const mCompositor;
-  const ScreenPoint mOriginalOffset;
-};
-
 class ScopedContextSurfaceOverride {
 public:
   ScopedContextSurfaceOverride(GLContextEGL* aContext, void* aSurface) :
     mContext(aContext)
   {
     MOZ_ASSERT(aSurface);
     mContext->SetEGLSurfaceOverride(aSurface);
     mContext->MakeCurrent(true);
@@ -1160,16 +1175,69 @@ LayerManagerComposite::RenderToPresentat
 
   const IntRect clipRect = IntRect::Truncate(0, 0, actualWidth, actualHeight);
 
   RootLayer()->Prepare(RenderTargetIntRect::FromUnknownRect(clipRect));
   RootLayer()->RenderLayer(clipRect, Nothing());
 
   mCompositor->EndFrame();
 }
+
+int32_t
+LayerManagerComposite::RenderToolbar()
+{
+  int32_t toolbarHeight = 0;
+
+  // If GetTargetContext returns null we are drawing to the screen so draw the toolbar offset if present.
+  if (mCompositor->GetTargetContext() == nullptr) {
+    if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) {
+      AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+      MOZ_ASSERT(animator);
+      toolbarHeight = animator->GetCurrentToolbarHeight();
+      if (toolbarHeight > 0) {
+        EffectChain effects;
+        effects.mPrimaryEffect = animator->GetToolbarEffect(mCompositor->AsCompositorOGL());
+        if (!effects.mPrimaryEffect) {
+          // No toolbar texture so just draw a red square
+          effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 0, 0));
+        }
+        mCompositor->DrawQuad(gfx::Rect(0, 0, mRenderBounds.width, toolbarHeight),
+                              IntRect(0, 0, mRenderBounds.width, toolbarHeight), effects, 1.0, gfx::Matrix4x4());
+
+        // Move the content down the surface by the toolbar's height so they don't overlap
+        gfx::Matrix4x4 mat = mCompositor->AsCompositorOGL()->GetProjMatrix();
+        mat.PreTranslate(0.0f, float(toolbarHeight), 0.0f);
+        mCompositor->AsCompositorOGL()->SetProjMatrix(mat);
+      }
+    }
+  }
+
+  return toolbarHeight;
+}
+
+// Used by robocop tests to get a snap shot of the frame buffer.
+void
+LayerManagerComposite::HandlePixelsTarget()
+{
+  if (mScreenPixelsTarget) {
+    int32_t bufferWidth = mRenderBounds.width;
+    int32_t bufferHeight = mRenderBounds.height;
+    ipc::Shmem mem;
+    if (!mScreenPixelsTarget->AllocPixelBuffer(bufferWidth * bufferHeight * sizeof(uint32_t), &mem)) {
+      // Failed to alloc shmem, Just bail out.
+      return;
+    }
+    CompositorOGL* compositor = mCompositor->AsCompositorOGL();
+    GLContext* gl = compositor->gl();
+    MOZ_ASSERT(gl);
+    gl->fReadPixels(0, 0, bufferWidth, bufferHeight, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, mem.get<uint8_t>());
+    Unused << mScreenPixelsTarget->SendScreenPixels(bufferWidth, bufferHeight, mem);
+    mScreenPixelsTarget = nullptr;
+  }
+}
 #endif
 
 class TextLayerComposite : public TextLayer,
                            public LayerComposite
 {
 public:
   explicit TextLayerComposite(LayerManagerComposite *aManager)
     : TextLayer(aManager, nullptr)
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -58,16 +58,19 @@ class ImageLayer;
 class ImageLayerComposite;
 class LayerComposite;
 class RefLayerComposite;
 class PaintedLayerComposite;
 class TextRenderer;
 class CompositingRenderTarget;
 struct FPSState;
 class PaintCounter;
+#if defined(MOZ_WIDGET_ANDROID)
+class UiCompositorControllerParent;
+#endif // defined(MOZ_WIDGET_ANDROID)
 
 static const int kVisualWarningDuration = 150; // ms
 
 // An implementation of LayerManager that acts as a pair with ClientLayerManager
 // and is mirrored across IPDL. This gets managed/updated by LayerTransactionParent.
 class HostLayerManager : public LayerManager
 {
 public:
@@ -208,16 +211,23 @@ protected:
 
   // Render time for the current composition.
   TimeStamp mCompositionTime;
 
   // When nonnull, during rendering, some compositable indicated that it will
   // change its rendering at this time. In order not to miss it, we composite
   // on every vsync until this time occurs (this is the latest such time).
   TimeStamp mCompositeUntilTime;
+#if defined(MOZ_WIDGET_ANDROID)
+public:
+  // Used by UiCompositorControllerParent to set it self as the target for the
+  // contents of the frame buffer after a composite.
+  // Implemented in LayerManagerComposite
+  virtual void RequestScreenPixels(UiCompositorControllerParent* aController) {}
+#endif // defined(MOZ_WIDGET_ANDROID)
 };
 
 // A layer manager implementation that uses the Compositor API
 // to render layers.
 class LayerManagerComposite final : public HostLayerManager
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::IntSize IntSize;
@@ -424,16 +434,18 @@ private:
   void UpdateAndRender();
 
   /**
    * Render the current layer tree to the active target.
    */
   void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion);
 #if defined(MOZ_WIDGET_ANDROID)
   void RenderToPresentationSurface();
+  int32_t RenderToolbar();
+  void HandlePixelsTarget();
 #endif
 
   /**
    * We need to know our invalid region before we're ready to render.
    */
   void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds);
 
   /**
@@ -477,16 +489,24 @@ private:
 
 #ifdef USE_SKIA
   /**
    * Render paint and composite times above the frame.
    */
   void DrawPaintTimes(Compositor* aCompositor);
   RefPtr<PaintCounter> mPaintCounter;
 #endif
+#if defined(MOZ_WIDGET_ANDROID)
+  UiCompositorControllerParent* mScreenPixelsTarget;
+public:
+  virtual void RequestScreenPixels(UiCompositorControllerParent* aController)
+  {
+    mScreenPixelsTarget = aController;
+  }
+#endif // defined(MOZ_WIDGET_ANDROID)
 };
 
 /**
  * Compositor layers are for use with OMTC on the compositor thread only. There
  * must be corresponding Client layers on the content thread. For composite
  * layers, the layer manager only maintains the layer tree.
  */
 class HostLayer