Bug 895358 - Part 2, Enable progressive tile rendering in B2G; r=BenWa,kats,Cwiiis

This commit is contained in:
Randall Barker 2013-12-17 13:41:00 -08:00
parent b4a3fdd32a
commit ffd53db5e1
12 changed files with 502 additions and 16 deletions

View File

@ -85,6 +85,15 @@ pref("mozilla.widget.use-buffer-pixmap", true);
pref("mozilla.widget.disable-native-theme", true);
pref("layout.reflow.synthMouseMove", false);
pref("layers.enable-tiles", false);
/*
Cross Process Mutex is not supported on Mac OS X so progressive
paint can not be enabled for B2G on Mac OS X desktop
*/
#ifdef MOZ_WIDGET_COCOA
pref("layers.progressive-paint", false);
#else
pref("layers.progressive-paint", false);
#endif
/* download manager (don't show the window or alert) */
pref("browser.download.useDownloadDir", true);

View File

@ -8,6 +8,7 @@
#include "ClientTiledThebesLayer.h" // for ClientTiledThebesLayer
#include "GeckoProfiler.h" // for PROFILER_LABEL
#include "ClientLayerManager.h" // for ClientLayerManager
#include "CompositorChild.h" // for CompositorChild
#include "gfxContext.h" // for gfxContext, etc
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxRect.h" // for gfxRect
@ -77,8 +78,8 @@ namespace layers {
TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
ClientLayerManager* aManager)
: CompositableClient(aManager->AsShadowForwarder())
, mTiledBuffer(aThebesLayer, aManager)
, mLowPrecisionTiledBuffer(aThebesLayer, aManager)
, mTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
, mLowPrecisionTiledBuffer(aThebesLayer, aManager, &mSharedFrameMetricsHelper)
{
MOZ_COUNT_CTOR(TiledContentClient);
@ -101,11 +102,138 @@ TiledContentClient::LockCopyAndWrite(TiledBufferType aType)
buffer->ClearPaintedRegion();
}
SharedFrameMetricsHelper::SharedFrameMetricsHelper()
: mLastProgressiveUpdateWasLowPrecision(false)
, mProgressiveUpdateWasInDanger(false)
{
MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
}
SharedFrameMetricsHelper::~SharedFrameMetricsHelper()
{
MOZ_COUNT_DTOR(SharedFrameMetricsHelper);
}
static inline bool
FuzzyEquals(float a, float b) {
return (fabsf(a - b) < 1e-6);
}
bool
SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
ContainerLayer* aLayer,
bool aHasPendingNewThebesContent,
bool aLowPrecision,
ScreenRect& aCompositionBounds,
CSSToScreenScale& aZoom)
{
MOZ_ASSERT(aLayer);
CompositorChild* compositor = CompositorChild::Get();
if (!compositor) {
FindFallbackContentFrameMetrics(aLayer, aCompositionBounds, aZoom);
return false;
}
const FrameMetrics& contentMetrics = aLayer->GetFrameMetrics();
FrameMetrics compositorMetrics;
if (!compositor->LookupCompositorFrameMetrics(contentMetrics.mScrollId,
compositorMetrics)) {
FindFallbackContentFrameMetrics(aLayer, aCompositionBounds, aZoom);
return false;
}
aCompositionBounds = ScreenRect(compositorMetrics.mCompositionBounds);
aZoom = compositorMetrics.mZoom;
// Reset the checkerboard risk flag when switching to low precision
// rendering.
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
// Skip low precision rendering until we're at risk of checkerboarding.
if (!mProgressiveUpdateWasInDanger) {
return true;
}
mProgressiveUpdateWasInDanger = false;
}
mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
// Always abort updates if the resolution has changed. There's no use
// in drawing at the incorrect resolution.
if (!FuzzyEquals(compositorMetrics.mZoom.scale, contentMetrics.mZoom.scale)) {
return true;
}
// Never abort drawing if we can't be sure we've sent a more recent
// display-port. If we abort updating when we shouldn't, we can end up
// with blank regions on the screen and we open up the risk of entering
// an endless updating cycle.
if (fabsf(contentMetrics.mScrollOffset.x - compositorMetrics.mScrollOffset.x) <= 2 &&
fabsf(contentMetrics.mScrollOffset.y - compositorMetrics.mScrollOffset.y) <= 2 &&
fabsf(contentMetrics.mDisplayPort.x - compositorMetrics.mDisplayPort.x) <= 2 &&
fabsf(contentMetrics.mDisplayPort.y - compositorMetrics.mDisplayPort.y) <= 2 &&
fabsf(contentMetrics.mDisplayPort.width - compositorMetrics.mDisplayPort.width) <= 2 &&
fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height)) {
return false;
}
// When not a low precision pass and the page is in danger of checker boarding
// abort update.
if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
if (AboutToCheckerboard(contentMetrics, compositorMetrics)) {
mProgressiveUpdateWasInDanger = true;
return true;
}
}
// Abort drawing stale low-precision content if there's a more recent
// display-port in the pipeline.
if (aLowPrecision && !aHasPendingNewThebesContent) {
return true;
}
return false;
}
void
SharedFrameMetricsHelper::FindFallbackContentFrameMetrics(ContainerLayer* aLayer,
ScreenRect& aCompositionBounds,
CSSToScreenScale& aZoom) {
if (!aLayer) {
return;
}
ContainerLayer* layer = aLayer;
const FrameMetrics* contentMetrics = &(layer->GetFrameMetrics());
// Walk up the layer tree until a valid composition bounds is found
while (layer && contentMetrics->mCompositionBounds.IsEmpty()) {
layer = layer->GetParent();
contentMetrics = layer ? &(layer->GetFrameMetrics()) : contentMetrics;
}
MOZ_ASSERT(!contentMetrics->mCompositionBounds.IsEmpty());
aCompositionBounds = ScreenRect(contentMetrics->mCompositionBounds);
aZoom = contentMetrics->mZoom;
return;
}
bool
SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetrics,
const FrameMetrics& aCompositorMetrics)
{
return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.mScrollOffset);
}
BasicTiledLayerBuffer::BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
ClientLayerManager* aManager)
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper)
: mThebesLayer(aThebesLayer)
, mManager(aManager)
, mLastPaintOpaque(false)
, mSharedFrameMetricsHelper(aHelper)
{
}
@ -193,7 +321,8 @@ BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
/* static */ BasicTiledLayerBuffer
BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator,
const SurfaceDescriptorTiles& aDescriptor)
const SurfaceDescriptorTiles& aDescriptor,
SharedFrameMetricsHelper* aHelper)
{
return BasicTiledLayerBuffer(aAllocator,
aDescriptor.validRegion(),
@ -201,7 +330,8 @@ BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator,
aDescriptor.tiles(),
aDescriptor.retainedWidth(),
aDescriptor.retainedHeight(),
aDescriptor.resolution());
aDescriptor.resolution(),
aHelper);
}
void
@ -474,9 +604,25 @@ BasicTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvali
// caused by there being an incoming, more relevant paint.
ScreenRect compositionBounds;
CSSToScreenScale zoom;
if (mManager->ProgressiveUpdateCallback(!staleRegion.Contains(aInvalidRegion),
compositionBounds, zoom,
!drawingLowPrecision)) {
#if defined(MOZ_WIDGET_ANDROID)
bool abortPaint = mManager->ProgressiveUpdateCallback(!staleRegion.Contains(aInvalidRegion),
compositionBounds, zoom,
!drawingLowPrecision);
#else
MOZ_ASSERT(mSharedFrameMetricsHelper);
ContainerLayer* parent = mThebesLayer->AsLayer()->GetParent();
bool abortPaint =
mSharedFrameMetricsHelper->UpdateFromCompositorFrameMetrics(
parent,
!staleRegion.Contains(aInvalidRegion),
drawingLowPrecision,
compositionBounds,
zoom);
#endif
if (abortPaint) {
// We ignore if front-end wants to abort if this is the first,
// non-low-precision paint, as in that situation, we're about to override
// front-end's page/viewport metrics.

View File

@ -168,6 +168,47 @@ struct BasicTiledLayerPaintData {
class ClientTiledThebesLayer;
class ClientLayerManager;
class SharedFrameMetricsHelper
{
public:
SharedFrameMetricsHelper();
~SharedFrameMetricsHelper();
/**
* This is called by the BasicTileLayer to determine if it is still interested
* in the update of this display-port to continue. We can return true here
* to abort the current update and continue with any subsequent ones. This
* is useful for slow-to-render pages when the display-port starts lagging
* behind enough that continuing to draw it is wasted effort.
*/
bool UpdateFromCompositorFrameMetrics(ContainerLayer* aLayer,
bool aHasPendingNewThebesContent,
bool aLowPrecision,
ScreenRect& aCompositionBounds,
CSSToScreenScale& aZoom);
/**
* When a shared FrameMetrics can not be found for a given layer,
* this function is used to find the first non-empty composition bounds
* by traversing up the layer tree.
*/
void FindFallbackContentFrameMetrics(ContainerLayer* aLayer,
ScreenRect& aCompositionBounds,
CSSToScreenScale& aZoom);
/**
* Determines if the compositor's upcoming composition bounds has fallen
* outside of the contents display port. If it has then the compositor
* will start to checker board. Checker boarding is when the compositor
* tries to composite a tile and it is not available. Historically
* a tile with a checker board pattern was used. Now a blank tile is used.
*/
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
const FrameMetrics& aCompositorMetrics);
private:
bool mLastProgressiveUpdateWasLowPrecision;
bool mProgressiveUpdateWasInDanger;
};
/**
* Provide an instance of TiledLayerBuffer backed by image surfaces.
* This buffer provides an implementation to ValidateTile using a
@ -181,11 +222,13 @@ class BasicTiledLayerBuffer
public:
BasicTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
ClientLayerManager* aManager);
ClientLayerManager* aManager,
SharedFrameMetricsHelper* aHelper);
BasicTiledLayerBuffer()
: mThebesLayer(nullptr)
, mManager(nullptr)
, mLastPaintOpaque(false)
, mSharedFrameMetricsHelper(nullptr)
{}
BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator,
@ -194,8 +237,10 @@ public:
const InfallibleTArray<TileDescriptor>& aTiles,
int aRetainedWidth,
int aRetainedHeight,
float aResolution)
float aResolution,
SharedFrameMetricsHelper* aHelper)
{
mSharedFrameMetricsHelper = aHelper;
mValidRegion = aValidRegion;
mPaintedRegion = aPaintedRegion;
mRetainedWidth = aRetainedWidth;
@ -249,7 +294,8 @@ public:
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor);
const SurfaceDescriptorTiles& aDescriptor,
SharedFrameMetricsHelper* aHelper);
protected:
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
@ -283,6 +329,7 @@ private:
nsRefPtr<gfxImageSurface> mSinglePaintBuffer;
RefPtr<gfx::DrawTarget> mSinglePaintDrawTarget;
nsIntPoint mSinglePaintBufferOffset;
SharedFrameMetricsHelper* mSharedFrameMetricsHelper;
BasicTiledLayerTile ValidateTileInternal(BasicTiledLayerTile aTile,
const nsIntPoint& aTileOrigin,
@ -341,6 +388,7 @@ public:
void LockCopyAndWrite(TiledBufferType aType);
private:
SharedFrameMetricsHelper mSharedFrameMetricsHelper;
BasicTiledLayerBuffer mTiledBuffer;
BasicTiledLayerBuffer mLowPrecisionTiledBuffer;
};

View File

@ -156,6 +156,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
apzc = new AsyncPanZoomController(aLayersId, this, state->mController,
AsyncPanZoomController::USE_GESTURE_DETECTOR);
apzc->SetCompositorParent(aCompositor);
apzc->SetCrossProcessCompositorParent(state->mCrossProcessParent);
} else {
// If there was already an APZC for the layer clear the tree pointers
// so that it doesn't continue pointing to APZCs that should no longer

View File

@ -80,13 +80,13 @@ TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor)
{
if (aTiledDescriptor.resolution() < 1) {
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload,
mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion());
mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingLowPrecisionUpload = true;
} else {
mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor, nullptr);
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
mMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingUpload = true;

View File

@ -14,10 +14,12 @@
#include "FrameMetrics.h" // for FrameMetrics, etc
#include "GestureEventListener.h" // for GestureEventListener
#include "InputData.h" // for MultiTouchInput, etc
#include "LayerTransactionParent.h" // for LayerTransactionParent
#include "Units.h" // for CSSRect, CSSPoint, etc
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "base/tracked.h" // for FROM_HERE
#include "gfxPlatform.h" // for gfxPlatform::UseProgressiveTilePainting
#include "gfxTypes.h" // for gfxFloat
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_*
@ -38,8 +40,10 @@
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
#include "mozilla/layers/Axis.h" // for AxisX, AxisY, Axis, etc
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/PCompositorParent.h" // for PCompositorParent
#include "mozilla/layers/TaskThrottler.h" // for TaskThrottler
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/unused.h" // for unused
#include "nsAlgorithm.h" // for clamped
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsCOMPtr.h" // for already_AddRefed
@ -53,6 +57,7 @@
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
#include "nsThreadUtils.h" // for NS_IsMainThread
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "SharedMemoryBasic.h" // for SharedMemoryBasic
// #define APZC_ENABLE_RENDERTRACE
@ -242,6 +247,11 @@ static bool gAsyncZoomDisabled = false;
*/
static bool gCrossSlideEnabled = false;
/**
* Pref that enables progressive tile painting
*/
static bool gUseProgressiveTilePainting = false;
/**
* Is aAngle within the given threshold of the horizontal axis?
* @param aAngle an angle in radians in the range [0, pi]
@ -272,6 +282,9 @@ static inline void LogRendertraceRect(const ScrollableLayerGuid& aGuid, const ch
static TimeStamp sFrameTime;
// Counter used to give each APZC a unique id
static uint32_t sAsyncPanZoomControllerCount = 0;
static TimeStamp
GetFrameTime() {
if (sFrameTime.IsNull()) {
@ -361,6 +374,7 @@ AsyncPanZoomController::InitializeGlobalState()
Preferences::AddBoolVarCache(&gAsyncZoomDisabled, "apz.asynczoom.disabled", gAsyncZoomDisabled);
Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apz.cross_slide.enabled", gCrossSlideEnabled);
Preferences::AddIntVarCache(&gAxisLockMode, "apz.axis_lock_mode", gAxisLockMode);
gUseProgressiveTilePainting = gfxPlatform::UseProgressiveTilePainting();
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
@ -373,6 +387,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
GeckoContentController* aGeckoContentController,
GestureBehavior aGestures)
: mLayersId(aLayersId),
mCrossProcessCompositorParent(nullptr),
mPaintThrottler(GetFrameTime()),
mGeckoContentController(aGeckoContentController),
mRefPtrMonitor("RefPtrMonitor"),
@ -390,7 +405,10 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mCurrentAsyncScrollOffset(0, 0),
mAsyncScrollTimeoutTask(nullptr),
mHandlingTouchQueue(false),
mTreeManager(aTreeManager)
mTreeManager(aTreeManager),
mAPZCId(sAsyncPanZoomControllerCount++),
mSharedFrameMetricsBuffer(nullptr),
mSharedLock(nullptr)
{
MOZ_COUNT_CTOR(AsyncPanZoomController);
@ -403,6 +421,18 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
}
AsyncPanZoomController::~AsyncPanZoomController() {
PCompositorParent* compositor =
(mCrossProcessCompositorParent ? mCrossProcessCompositorParent : mCompositorParent.get());
// Only send the release message if the SharedFrameMetrics has been created.
if (compositor && mSharedFrameMetricsBuffer) {
unused << compositor->SendReleaseSharedCompositorFrameMetrics(mFrameMetrics.mScrollId, mAPZCId);
}
delete mSharedFrameMetricsBuffer;
delete mSharedLock;
MOZ_COUNT_DTOR(AsyncPanZoomController);
}
@ -548,6 +578,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
ReentrantMonitorAutoEnter lock(mMonitor);
RequestContentRepaint();
ScheduleComposite();
UpdateSharedCompositorFrameMetrics();
}
// Fall through.
case FLING:
@ -652,6 +683,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
{
ReentrantMonitorAutoEnter lock(mMonitor);
RequestContentRepaint();
UpdateSharedCompositorFrameMetrics();
}
mX.EndTouch();
mY.EndTouch();
@ -760,6 +792,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
ScheduleComposite();
// We don't want to redraw on every scale, so don't use
// RequestContentRepaint()
UpdateSharedCompositorFrameMetrics();
}
mLastZoomFocus = focusPoint;
@ -783,6 +816,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
ReentrantMonitorAutoEnter lock(mMonitor);
ScheduleComposite();
RequestContentRepaint();
UpdateSharedCompositorFrameMetrics();
}
return nsEventStatus_eConsumeNoDefault;
@ -996,6 +1030,7 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
if (timePaintDelta.ToMilliseconds() > gPanRepaintInterval) {
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
}
}
@ -1104,6 +1139,10 @@ void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorPa
mCompositorParent = aCompositorParent;
}
void AsyncPanZoomController::SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent) {
mCrossProcessCompositorParent = aCrossProcessCompositorParent;
}
void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
mFrameMetrics.mScrollOffset += aOffset;
}
@ -1332,6 +1371,7 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime)
SendAsyncScrollEvent();
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
mLastSampleTime = aSampleTime;
return true;
}
@ -1450,6 +1490,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
mY.CancelTouch();
mFrameMetrics = aLayerMetrics;
ShareCompositorFrameMetrics();
SetState(NOTHING);
} else {
// If we're not taking the aLayerMetrics wholesale we still need to pull
@ -1477,6 +1518,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
if (needContentRepaint) {
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
}
const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
@ -1709,5 +1751,64 @@ ScrollableLayerGuid AsyncPanZoomController::GetGuid()
return ScrollableLayerGuid(mLayersId, mFrameMetrics);
}
void AsyncPanZoomController::UpdateSharedCompositorFrameMetrics()
{
mMonitor.AssertCurrentThreadIn();
FrameMetrics* frame = mSharedFrameMetricsBuffer ?
static_cast<FrameMetrics*>(mSharedFrameMetricsBuffer->memory()) : nullptr;
if (gUseProgressiveTilePainting && frame && mSharedLock) {
mSharedLock->Lock();
*frame = mFrameMetrics;
mSharedLock->Unlock();
}
}
void AsyncPanZoomController::ShareCompositorFrameMetrics() {
PCompositorParent* compositor =
(mCrossProcessCompositorParent ? mCrossProcessCompositorParent : mCompositorParent.get());
// Only create the shared memory buffer if it hasn't already been created,
// we are using progressive tile painting, and we have a
// compositor to pass the shared memory back to the content process/thread.
if (!mSharedFrameMetricsBuffer && gUseProgressiveTilePainting && compositor) {
// Create shared memory and initialize it with the current FrameMetrics value
mSharedFrameMetricsBuffer = new ipc::SharedMemoryBasic;
FrameMetrics* frame = nullptr;
mSharedFrameMetricsBuffer->Create(sizeof(FrameMetrics));
mSharedFrameMetricsBuffer->Map(sizeof(FrameMetrics));
frame = static_cast<FrameMetrics*>(mSharedFrameMetricsBuffer->memory());
if (frame) {
{ // scope the monitor, only needed to copy the FrameMetrics.
ReentrantMonitorAutoEnter lock(mMonitor);
*frame = mFrameMetrics;
}
// Get the process id of the content process
base::ProcessId pId = compositor->OtherProcess();
ipc::SharedMemoryBasic::Handle mem = ipc::SharedMemoryBasic::NULLHandle();
// Get the shared memory handle to share with the content process
mSharedFrameMetricsBuffer->ShareToProcess(pId, &mem);
// Get the cross process mutex handle to share with the content process
mSharedLock = new CrossProcessMutex("AsyncPanZoomControlLock");
CrossProcessMutexHandle handle = mSharedLock->ShareToProcess(pId);
// Send the shared memory handle and cross process handle to the content
// process by an asynchronous ipc call. Include the APZC unique ID
// so the content process know which APZC sent this shared FrameMetrics.
if (!compositor->SendSharedCompositorFrameMetrics(mem, handle, mAPZCId)) {
APZC_LOG("Failed to share FrameMetrics with content process.");
}
}
}
}
}
}

View File

@ -7,6 +7,7 @@
#ifndef mozilla_layers_AsyncPanZoomController_h
#define mozilla_layers_AsyncPanZoomController_h
#include "CrossProcessMutex.h"
#include "GeckoContentController.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
@ -22,12 +23,20 @@
#include "base/message_loop.h"
namespace mozilla {
namespace ipc {
class SharedMemoryBasic;
}
namespace layers {
struct ScrollableLayerGuid;
class CompositorParent;
class GestureEventListener;
class ContainerLayer;
class PCompositorParent;
class ViewTransform;
class APZCTreeManager;
class AsyncPanZoomAnimation;
@ -180,6 +189,14 @@ public:
*/
void SetCompositorParent(CompositorParent* aCompositorParent);
/**
* The platform implementation must set the cross process compositor if
* there is one associated with the layer tree. The cross process compositor
* allows the APZC to share its FrameMetrics with the content process.
* The shared FrameMetrics is used in progressive paint updates.
*/
void SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent);
// --------------------------------------------------------------------------
// These methods can be called from any thread.
//
@ -544,6 +561,7 @@ private:
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
PCompositorParent* mCrossProcessCompositorParent;
TaskThrottler mPaintThrottler;
/* Access to the following two fields is protected by the mRefPtrMonitor,
@ -704,6 +722,9 @@ public:
}
private:
/* Unique id assigned to each APZC. Used with ViewID to uniquely identify
* shared FrameMeterics used in progressive tile painting. */
const uint32_t mAPZCId;
/* This is the visible region of the layer that this APZC corresponds to, in
* that layer's screen pixels (the same coordinate system in which this APZC
* receives events in ReceiveInputEvent()). */
@ -713,6 +734,20 @@ private:
gfx3DMatrix mAncestorTransform;
/* This is the CSS transform for this APZC's layer. */
gfx3DMatrix mCSSTransform;
ipc::SharedMemoryBasic* mSharedFrameMetricsBuffer;
CrossProcessMutex* mSharedLock;
/**
* Called when ever mFrameMetrics is updated so that if it is being
* shared with the content process the shared FrameMetrics may be updated.
*/
void UpdateSharedCompositorFrameMetrics();
/**
* Create a shared memory buffer for containing the FrameMetrics and
* a CrossProcessMutex that may be shared with the content process
* for use in progressive tiled update calculations.
*/
void ShareCompositorFrameMetrics();
};
class AsyncPanZoomAnimation {

View File

@ -52,6 +52,18 @@ CompositorChild::Destroy()
SendStop();
}
bool
CompositorChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId,
FrameMetrics& aFrame)
{
SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
if (data) {
data->CopyFrameMetrics(&aFrame);
return true;
}
return false;
}
/*static*/ PCompositorChild*
CompositorChild::Create(Transport* aTransport, ProcessId aOtherProcess)
{
@ -73,7 +85,7 @@ CompositorChild::Create(Transport* aTransport, ProcessId aOtherProcess)
return sCompositor = child.forget().get();
}
/*static*/ PCompositorChild*
/*static*/ CompositorChild*
CompositorChild::Get()
{
// This is only expected to be used in child processes.
@ -131,6 +143,80 @@ CompositorChild::ActorDestroy(ActorDestroyReason aWhy)
NewRunnableMethod(this, &CompositorChild::Release));
}
bool
CompositorChild::RecvSharedCompositorFrameMetrics(
const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
const CrossProcessMutexHandle& handle,
const uint32_t& aAPZCId)
{
SharedFrameMetricsData* data = new SharedFrameMetricsData(metrics, handle, aAPZCId);
mFrameMetricsTable.Put(data->GetViewID(), data);
return true;
}
bool
CompositorChild::RecvReleaseSharedCompositorFrameMetrics(
const ViewID& aId,
const uint32_t& aAPZCId)
{
SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
// The SharedFrameMetricsData may have been removed previously if
// a SharedFrameMetricsData with the same ViewID but later APZCId had
// been store and over wrote it.
if (data && (data->GetAPZCId() == aAPZCId)) {
mFrameMetricsTable.Remove(aId);
}
return true;
}
CompositorChild::SharedFrameMetricsData::SharedFrameMetricsData(
const ipc::SharedMemoryBasic::Handle& metrics,
const CrossProcessMutexHandle& handle,
const uint32_t& aAPZCId) :
mBuffer(nullptr),
mMutex(nullptr),
mAPZCId(aAPZCId)
{
mBuffer = new ipc::SharedMemoryBasic(metrics);
mBuffer->Map(sizeof(FrameMetrics));
mMutex = new CrossProcessMutex(handle);
MOZ_COUNT_CTOR(SharedFrameMetricsData);
}
CompositorChild::SharedFrameMetricsData::~SharedFrameMetricsData()
{
// When the hash table deletes the class, delete
// the shared memory and mutex.
delete mMutex;
delete mBuffer;
MOZ_COUNT_DTOR(SharedFrameMetricsData);
}
void
CompositorChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame)
{
FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory());
MOZ_ASSERT(frame);
mMutex->Lock();
*aFrame = *frame;
mMutex->Unlock();
}
FrameMetrics::ViewID
CompositorChild::SharedFrameMetricsData::GetViewID()
{
FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory());
MOZ_ASSERT(frame);
// Not locking to read of mScrollId since it should not change after being
// initially set.
return frame->mScrollId;
}
uint32_t
CompositorChild::SharedFrameMetricsData::GetAPZCId()
{
return mAPZCId;
}
} // namespace layers
} // namespace mozilla

View File

@ -13,7 +13,9 @@
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/PCompositorChild.h"
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsClassHashtable.h" // for nsClassHashtable
#include "nsCOMPtr.h" // for nsCOMPtr
#include "nsHashKeys.h" // for nsUint64HashKey
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
class nsIObserver;
@ -23,6 +25,7 @@ namespace layers {
class ClientLayerManager;
class CompositorParent;
class FrameMetrics;
class CompositorChild : public PCompositorChild
{
@ -33,6 +36,13 @@ public:
void Destroy();
/**
* Lookup the FrameMetrics shared by the compositor process with the
* associated FrameMetrics::ViewID. The returned FrameMetrics is used
* in progressive paint calculations.
*/
bool LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, FrameMetrics&);
/**
* We're asked to create a new Compositor in response to an Opens()
* or Bridge() request from our parent process. The Transport is to
@ -41,7 +51,7 @@ public:
static PCompositorChild*
Create(Transport* aTransport, ProcessId aOtherProcess);
static PCompositorChild* Get();
static CompositorChild* Get();
static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
@ -58,10 +68,44 @@ protected:
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool RecvSharedCompositorFrameMetrics(const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
const CrossProcessMutexHandle& handle,
const uint32_t& aAPZCId) MOZ_OVERRIDE;
virtual bool RecvReleaseSharedCompositorFrameMetrics(const ViewID& aId,
const uint32_t& aAPZCId) MOZ_OVERRIDE;
private:
// Class used to store the shared FrameMetrics, mutex, and APZCId in a hash table
class SharedFrameMetricsData {
public:
SharedFrameMetricsData(
const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
const CrossProcessMutexHandle& handle,
const uint32_t& aAPZCId);
~SharedFrameMetricsData();
void CopyFrameMetrics(FrameMetrics* aFrame);
FrameMetrics::ViewID GetViewID();
uint32_t GetAPZCId();
private:
// Pointer to the class that allows access to the shared memory that contains
// the shared FrameMetrics
mozilla::ipc::SharedMemoryBasic* mBuffer;
CrossProcessMutex* mMutex;
// Unique ID of the APZC that is sharing the FrameMetrics
uint32_t mAPZCId;
};
nsRefPtr<ClientLayerManager> mLayerManager;
nsCOMPtr<nsIObserver> mMemoryPressureObserver;
// The ViewID of the FrameMetrics is used as the key for this hash table.
// While this should be safe to use since the ViewID is unique
nsClassHashtable<nsUint64HashKey, SharedFrameMetricsData> mFrameMetricsTable;
// When we're in a child process, this is the process-global
// compositor that we use to forward transactions directly to the
// compositor context in another process.

View File

@ -63,6 +63,7 @@ namespace layers {
CompositorParent::LayerTreeState::LayerTreeState()
: mParent(nullptr)
, mLayerManager(nullptr)
, mCrossProcessParent(nullptr)
{
}
@ -1105,6 +1106,7 @@ CrossProcessCompositorParent::AllocPLayerTransactionParent(const nsTArray<Layers
MOZ_ASSERT(aId != 0);
if (sIndirectLayerTrees[aId].mLayerManager) {
sIndirectLayerTrees[aId].mCrossProcessParent = this;
LayerManagerComposite* lm = sIndirectLayerTrees[aId].mLayerManager;
*aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier();
*aSuccess = true;

View File

@ -205,6 +205,10 @@ public:
nsRefPtr<GeckoContentController> mController;
CompositorParent* mParent;
LayerManagerComposite* mLayerManager;
// Pointer to the CrossProcessCompositorParent. Used by APZCs to share
// their FrameMetrics with the corresponding child process that holds
// the PCompositorChild
PCompositorParent* mCrossProcessParent;
TargetConfig mTargetConfig;
};

View File

@ -13,7 +13,11 @@ include "nsRegion.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
namespace mozilla {
namespace layers {
@ -81,6 +85,12 @@ parent:
// Notify the compositor that a region of the screen has been invalidated.
async NotifyRegionInvalidated(nsIntRegion region);
child:
// Send back Compositor Frame Metrics from APZCs so tiled layers can
// update progressively.
async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint32_t aAPZCId);
async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
};
} // layers