--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -47,24 +47,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
@@ -129,16 +130,19 @@ HostLayerManager::~HostLayerManager()
*/
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(aCompositor);
MOZ_ASSERT(aCompositor);
#ifdef USE_SKIA
mPaintCounter = nullptr;
#endif
}
@@ -817,16 +821,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");
@@ -902,16 +925,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(
@@ -941,16 +969,20 @@ LayerManagerComposite::Render(const nsIn
PopGroupForLayerEffects(previousTarget, clipRect.ToUnknownRect(),
grayscaleVal, invertVal, contrastVal);
}
// Allow widget to render a custom foreground.
mCompositor->GetWidget()->DrawWindowOverlay(
&widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
+#if defined(MOZ_WIDGET_ANDROID)
+ HandlePixelsTarget();
+#endif // defined(MOZ_WIDGET_ANDROID)
+
// Debugging
RenderDebugOverlay(actualBounds);
{
PROFILER_LABEL("LayerManagerComposite", "EndFrame",
js::ProfileEntry::Category::GRAPHICS);
mCompositor->EndFrame();
@@ -995,33 +1027,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);
@@ -1129,16 +1144,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
@@ -57,16 +57,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:
@@ -203,16 +206,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;
@@ -419,16 +429,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);
/**
@@ -474,16 +486,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