Bug 1294121 - Develop a continuous paint mode for Firefox. r=mattwoodrow

This commit is contained in:
Mason Chang 2016-08-15 19:59:26 -07:00
parent 69a8ca2b79
commit 8c9fb35901
20 changed files with 260 additions and 6 deletions

View File

@ -93,6 +93,7 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
: mPhase(PHASE_NONE)
, mWidget(aWidget)
, mLatestTransactionId(0)
, mLastPaintTime(TimeDuration::Forever())
, mTargetRotation(ROTATION_0)
, mRepeatTransaction(false)
, mIsRepeatTransaction(false)
@ -283,17 +284,24 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
mTransactionIncomplete = false;
// Apply pending tree updates before recomputing effective
// properties.
GetRoot()->ApplyPendingUpdatesToSubtree();
mPaintedLayerCallback = aCallback;
mPaintedLayerCallbackData = aCallbackData;
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
root->RenderLayer();
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
TimeStamp start = TimeStamp::Now();
root->RenderLayer();
mLastPaintTime = TimeStamp::Now() - start;
} else {
root->RenderLayer();
}
if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) {
GetRoot()->Mutated();
}
@ -623,6 +631,10 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
transactionStart = mTransactionStart;
}
if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) {
mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime);
}
// forward this transaction's changeset to our LayerManagerComposite
bool sent;
AutoTArray<EditReply, 10> replies;

View File

@ -303,7 +303,7 @@ private:
LayerRefArray mKeepAlive;
nsIWidget* mWidget;
/* PaintedLayer callbacks; valid at the end of a transaciton,
* while rendering */
DrawPaintedLayerCallback mPaintedLayerCallback;
@ -321,6 +321,7 @@ private:
RefPtr<TransactionIdAllocator> mTransactionIdAllocator;
uint64_t mLatestTransactionId;
TimeDuration mLastPaintTime;
// Sometimes we draw to targets that don't natively support
// landscape/portrait orientation. When we need to implement that

View File

@ -394,8 +394,7 @@ static void DrawDigits(unsigned int aValue,
Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
IntRect clipRect = IntRect(0, 0, 300, 100);
aCompositor->DrawQuad(drawRect, clipRect,
aEffectChain, opacity, transform);
aCompositor->DrawQuad(drawRect, clipRect, aEffectChain, opacity, transform);
}
}

View File

@ -12,6 +12,7 @@
#include "CompositableHost.h" // for CompositableHost
#include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc
#include "FPSCounter.h" // for FPSState, FPSCounter
#include "PaintCounter.h" // For PaintCounter
#include "FrameMetrics.h" // for FrameMetrics
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc
#include "ImageLayerComposite.h" // for ImageLayerComposite
@ -127,6 +128,8 @@ LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
, mGeometryChanged(true)
, mLastFrameMissedHWC(false)
, mWindowOverlayChanged(false)
, mLastPaintTime(TimeDuration::Forever())
, mRenderStartTime(TimeStamp::Now())
{
mTextRenderer = new TextRenderer(aCompositor);
MOZ_ASSERT(aCompositor);
@ -148,6 +151,7 @@ LayerManagerComposite::Destroy()
}
mRoot = nullptr;
mClonedLayerTreeProperties = nullptr;
mPaintCounter = nullptr;
mDestroyed = true;
}
}
@ -373,6 +377,7 @@ LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
NS_ASSERTION(!(aFlags & END_NO_COMPOSITE),
"Shouldn't get END_NO_COMPOSITE here");
mInTransaction = false;
mRenderStartTime = TimeStamp::Now();
if (!mIsCompositorReady) {
return;
@ -559,6 +564,7 @@ LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const
bool drawFps = gfxPrefs::LayersDrawFPS();
bool drawFrameCounter = gfxPrefs::DrawFrameCounter();
bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
bool drawPaintTimes = gfxPrefs::AlwaysPaint();
if (drawFps || drawFrameCounter) {
aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 256, 256));
@ -566,6 +572,20 @@ LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const
if (drawFrameColorBars) {
aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.height));
}
if (drawPaintTimes) {
aInvalidRegion.Or(aInvalidRegion, nsIntRect(PaintCounter::GetPaintRect()));
}
}
void
LayerManagerComposite::DrawPaintTimes(Compositor* aCompositor)
{
if (!mPaintCounter) {
mPaintCounter = new PaintCounter();
}
TimeDuration compositeTime = TimeStamp::Now() - mRenderStartTime;
mPaintCounter->Draw(aCompositor, mLastPaintTime, compositeTime);
}
static uint16_t sFrameCount = 0;
@ -575,6 +595,7 @@ LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds)
bool drawFps = gfxPrefs::LayersDrawFPS();
bool drawFrameCounter = gfxPrefs::DrawFrameCounter();
bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
bool drawPaintTimes = gfxPrefs::AlwaysPaint();
TimeStamp now = TimeStamp::Now();
@ -714,6 +735,10 @@ LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds)
// We intentionally overflow at 2^16.
sFrameCount++;
}
if (drawPaintTimes) {
DrawPaintTimes(mCompositor);
}
}
RefPtr<CompositingRenderTarget>

View File

@ -62,6 +62,7 @@ class PaintedLayerComposite;
class TextRenderer;
class CompositingRenderTarget;
struct FPSState;
class PaintCounter;
static const int kVisualWarningDuration = 150; // ms
@ -331,6 +332,8 @@ public:
void ForcePresent() { mCompositor->ForcePresent(); }
void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
private:
/** Region we're clipping our current drawing to. */
nsIntRegion mClippingRegion;
@ -352,6 +355,11 @@ private:
void RenderToPresentationSurface();
#endif
/**
* Render paint and composite times above the frame.
*/
void DrawPaintTimes(Compositor* aCompositor);
/**
* We need to know our invalid region before we're ready to render.
*/
@ -409,6 +417,9 @@ private:
bool mLastFrameMissedHWC;
bool mWindowOverlayChanged;
RefPtr<PaintCounter> mPaintCounter;
TimeDuration mLastPaintTime;
TimeStamp mRenderStartTime;
};
/**

View File

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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 "mozilla/gfx/Point.h" // for IntSize, Point
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/gfx/Types.h" // for Color, SurfaceFormat
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "mozilla/Snprintf.h"
#include "SkColor.h"
#include "mozilla/gfx/HelpersSkia.h"
#include "skia/include/core/SkBitmapDevice.h"
#include "PaintCounter.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
// Positioned below the chrome UI
IntRect PaintCounter::mRect = IntRect(0, 175, 300, 60);
PaintCounter::PaintCounter()
{
mFormat = SurfaceFormat::B8G8R8A8;
mSurface = Factory::CreateDataSourceSurface(mRect.Size(), mFormat);
mStride = mSurface->Stride();
SkBitmap bitmap;
bitmap.setInfo(MakeSkiaImageInfo(mRect.Size(), mFormat), mStride);
bitmap.setPixels(mSurface->GetData());
bitmap.eraseColor(SK_ColorWHITE);
mCanvas.adopt(new SkCanvas(bitmap));
}
PaintCounter::~PaintCounter()
{
mSurface = nullptr;
mTextureSource = nullptr;
mTexturedEffect = nullptr;
}
void
PaintCounter::Draw(Compositor* aCompositor, TimeDuration aPaintTime, TimeDuration aCompositeTime) {
const int buffer_size = 48;
char buffer[buffer_size];
snprintf(buffer, buffer_size, "P: %.2f C: %.2f",
aPaintTime.ToMilliseconds(),
aCompositeTime.ToMilliseconds());
SkPaint paint;
paint.setTextSize(32);
paint.setColor(SkColorSetRGB(0, 255, 0));
paint.setAntiAlias(true);
mCanvas->clear(SK_ColorTRANSPARENT);
mCanvas->drawText(buffer, strlen(buffer), 10, 30, paint);
mCanvas->flush();
if (!mTextureSource) {
mTextureSource = aCompositor->CreateDataTextureSource();
mTexturedEffect = CreateTexturedEffect(mFormat, mTextureSource,
SamplingFilter::POINT, true);
mTexturedEffect->mTextureCoords = Rect(0, 0, 1.0f, 1.0f);
}
mTextureSource->Update(mSurface);
EffectChain effectChain;
effectChain.mPrimaryEffect = mTexturedEffect;
gfx::Matrix4x4 identity;
Rect rect(mRect.x, mRect.y, mRect.width, mRect.height);
aCompositor->DrawQuad(rect, mRect, effectChain, 1.0, identity);
}
} // end namespace layers
} // end namespace mozilla

View File

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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 mozilla_layers_PaintCounter_h_
#define mozilla_layers_PaintCounter_h_
#include <map> // for std::map
#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "skia/include/core/SkCanvas.h"
#include "mozilla/gfx/HelpersSkia.h"
namespace mozilla {
namespace layers {
class Compositor;
using namespace mozilla::gfx;
using namespace mozilla::gl;
// Keeps track and paints how long a full invalidation paint takes to rasterize
// and composite.
class PaintCounter {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaintCounter)
PaintCounter();
void Draw(Compositor* aCompositor, TimeDuration aPaintTime, TimeDuration aCompositeTime);
static IntRect GetPaintRect() { return PaintCounter::mRect; }
private:
virtual ~PaintCounter();
SurfaceFormat mFormat;
RefPtrSkia<SkCanvas> mCanvas;
IntSize mSize;
int mStride;
RefPtr<DataSourceSurface> mSurface;
RefPtr<DataTextureSource> mTextureSource;
RefPtr<TexturedEffect> mTexturedEffect;
static IntRect mRect;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_opengl_PaintCounter_h_

View File

@ -615,6 +615,7 @@ CompositorBridgeParent::CompositorBridgeParent(CSSToLayoutDeviceScale aScale,
, mForceCompositionTask(nullptr)
, mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
, mCompositorScheduler(nullptr)
, mPaintTime(TimeDuration::Forever())
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
, mLastPluginUpdateLayerTreeId(0)
, mDeferPluginWindows(false)
@ -1078,6 +1079,18 @@ CompositorBridgeParent::ScheduleTask(already_AddRefed<CancelableRunnable> task,
}
}
void
CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree,
const TimeDuration& aPaintTime)
{
// We get a lot of paint timings for things with empty transactions.
if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) {
return;
}
mLayerManager->SetPaintTime(aPaintTime);
}
void
CompositorBridgeParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
bool aScheduleComposite, uint32_t aPaintSequenceNumber,
@ -2130,6 +2143,19 @@ public:
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() override { return this; }
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override {
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorBridgeParent::LayerTreeState* state =
CompositorBridgeParent::GetIndirectShadowTree(id);
if (!state || !state->mParent) {
return;
}
state->mParent->UpdatePaintTime(aLayerTree, aPaintTime);
}
protected:
void OnChannelConnected(int32_t pid) override {
mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();

View File

@ -372,6 +372,9 @@ public:
bool aScheduleComposite, uint32_t aPaintSequenceNumber,
bool aIsRepeatTransaction, bool aHitTestUpdate);
void UpdatePaintTime(LayerTransactionParent* aLayerTree,
const TimeDuration& aPaintTime) override;
/**
* Check rotation info and schedule a rendering task if needed.
* Only can be called from compositor thread.
@ -630,6 +633,8 @@ protected:
// mSelfRef is cleared in DeferredDestroy which is scheduled by ActorDestroy.
RefPtr<CompositorBridgeParent> mSelfRef;
TimeDuration mPaintTime;
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
// cached plugin data used to reduce the number of updates we request.
uint64_t mLastPluginUpdateLayerTreeId;

View File

@ -228,6 +228,14 @@ private:
InfallibleTArray<OpDestroy>* mActorsToDestroy;
};
bool
LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
const TimeDuration& aPaintTime)
{
mShadowLayersManager->UpdatePaintTime(this, aPaintTime);
return true;
}
bool
LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
InfallibleTArray<OpDestroy>&& aToDestroy,

View File

@ -109,6 +109,9 @@ protected:
virtual bool RecvShutdown() override;
virtual bool RecvPaintTime(const uint64_t& aTransactionId,
const TimeDuration& aPaintTime) override;
virtual bool RecvUpdate(EditArray&& cset,
OpDestroyArray&& aToDestroy,
const uint64_t& aFwdTransactionId,

View File

@ -58,6 +58,8 @@ parent:
int32_t paintSyncId)
returns (EditReply[] reply);
async PaintTime(uint64_t id, TimeDuration paintTime);
// We don't need to send a sync transaction if
// no transaction operate require a swap.
async UpdateNoSwap(Edit[] cset, OpDestroy[] toDestroy,

View File

@ -589,6 +589,15 @@ ShadowLayerForwarder::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::
}
}
void
ShadowLayerForwarder::SendPaintTime(uint64_t aId, TimeDuration aPaintTime)
{
if (!HasShadowManager() || !mShadowManager->IPCOpen() ||
!mShadowManager->SendPaintTime(aId, aPaintTime)) {
NS_WARNING("Could not send paint times over IPC");
}
}
bool
ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
const nsIntRegion& aRegionToClear,

View File

@ -265,6 +265,11 @@ public:
const nsIntRect& aPictureRect) override;
#endif
/**
* Used for debugging to tell the compositor how long this frame took to paint.
*/
void SendPaintTime(uint64_t aId, TimeDuration aPaintTime);
/**
* End the current transaction and forward it to LayerManagerComposite.
* |aReplies| are directions from the LayerManagerComposite to the

View File

@ -46,6 +46,7 @@ public:
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() { return nullptr; }
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
};
} // namespace layers

View File

@ -334,6 +334,7 @@ UNIFIED_SOURCES += [
'composite/ImageHost.cpp',
'composite/ImageLayerComposite.cpp',
'composite/LayerManagerComposite.cpp',
'composite/PaintCounter.cpp',
'composite/PaintedLayerComposite.cpp',
'composite/TextRenderer.cpp',
'composite/TextureHost.cpp',

View File

@ -386,6 +386,7 @@ private:
DECL_GFX_PREF(Live, "gfx.ycbcr.accurate-conversion", YCbCrAccurateConversion, bool, false);
DECL_GFX_PREF(Live, "gfx.content.use-native-pushlayer", UseNativePushLayer, bool, false);
DECL_GFX_PREF(Live, "gfx.content.always-paint", AlwaysPaint, bool, false);
// Disable surface sharing due to issues with compatible FBConfigs on
// NVIDIA drivers as described in bug 1193015.

View File

@ -1763,6 +1763,11 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
layerManager->BeginTransaction();
}
}
if (XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
if (widgetTransaction) {
layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
}

View File

@ -1928,6 +1928,10 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
ConfigureHighPrecision();
NS_ASSERTION(mInRefresh, "Still in refresh");
if (mPresContext->IsRoot() && XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
ScheduleViewManagerFlush();
}
}
void

View File

@ -4564,6 +4564,8 @@ pref("layers.componentalpha.enabled", true);
// Use the DT-backend implemented PushLayer
pref("gfx.content.use-native-pushlayer", false);
pref("gfx.content.always-paint", false);
#ifdef ANDROID
pref("gfx.apitrace.enabled",false);
#endif