From 53958037df1c9044c755fbfd539c9643bd6d48e4 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Thu, 29 Nov 2012 12:03:38 +0000 Subject: [PATCH] Bug 814437 - Fix checkerboard measurement when using a critical displayport. r=bgirard The checkerboard measurement depended on the displayport coverage of the viewport, which was calculated in LayerRenderer. When using a critical displayport, this value changes, but this was not being accounted for. We have all the context we need for this Gecko-side, so move this code into LayerManagerOGL::ComputeRenderIntegrity and account for displayport coverage correctly. --- gfx/layers/opengl/LayerManagerOGL.cpp | 80 ++++++++++++++++++++-- mobile/android/base/gfx/LayerRenderer.java | 42 +----------- 2 files changed, 76 insertions(+), 46 deletions(-) diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index e074ae62a4ce..cbbde71c886b 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -1702,20 +1702,87 @@ GetRegionArea(const nsIntRegion& aRegion) return area; } +static float +GetDisplayportCoverage(const gfx::Rect& aDisplayPort, + const gfx3DMatrix& aTransformToScreen, + const nsIntRect& aScreenRect) +{ + gfxRect transformedDisplayport = + aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x, + aDisplayPort.y, + aDisplayPort.width, + aDisplayPort.height)); + transformedDisplayport.RoundOut(); + nsIntRect displayport = nsIntRect(transformedDisplayport.x, + transformedDisplayport.y, + transformedDisplayport.width, + transformedDisplayport.height); + if (!displayport.Contains(aScreenRect)) { + nsIntRegion coveredRegion; + coveredRegion.And(aScreenRect, displayport); + return GetRegionArea(coveredRegion) / (float)(aScreenRect.width * aScreenRect.height); + } + + return 1.0f; +} + float LayerManagerOGL::ComputeRenderIntegrity() { // We only ever have incomplete rendering when progressive tiles are enabled. - if (!gfxPlatform::UseProgressiveTilePainting() || !GetRoot()) { + Layer* root = GetRoot(); + if (!gfxPlatform::UseProgressiveTilePainting() || !root) { return 1.f; } - // XXX We assume that mWidgetSize represents the 'screen' area. - gfx3DMatrix transform; - nsIntRect screenRect(0, 0, mWidgetSize.width, mWidgetSize.height); + const FrameMetrics& rootMetrics = root->AsContainerLayer()->GetFrameMetrics(); + nsIntRect screenRect(rootMetrics.mCompositionBounds.x, + rootMetrics.mCompositionBounds.y, + rootMetrics.mCompositionBounds.width, + rootMetrics.mCompositionBounds.height); + + float lowPrecisionMultiplier = 1.0f; + float highPrecisionMultiplier = 1.0f; +#ifdef MOZ_ANDROID_OMTC + // Use the transform on the primary scrollable layer and its FrameMetrics + // to find out how much of the viewport the current displayport covers + bool hasLowPrecision = true; + Layer* primaryScrollable = GetPrimaryScrollableLayer(); + if (primaryScrollable) { + // This is derived from the code in + // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree. + const gfx3DMatrix& rootTransform = root->GetTransform(); + float devPixelRatioX = 1 / rootTransform.GetXScale(); + float devPixelRatioY = 1 / rootTransform.GetYScale(); + + gfx3DMatrix transform = primaryScrollable->GetEffectiveTransform(); + transform.ScalePost(devPixelRatioX, devPixelRatioY, 1); + const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); + + // Work out how much of the critical display-port covers the screen + if (!metrics.mCriticalDisplayPort.IsEmpty()) { + hasLowPrecision = true; + highPrecisionMultiplier = + GetDisplayportCoverage(metrics.mCriticalDisplayPort, transform, screenRect); + } + + // Work out how much of the display-port covers the screen + if (!metrics.mDisplayPort.IsEmpty()) { + if (hasLowPrecision) { + lowPrecisionMultiplier = + GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + } else { + highPrecisionMultiplier = + GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + } + } + } +#endif + nsIntRegion screenRegion(screenRect); nsIntRegion lowPrecisionScreenRegion(screenRect); - ComputeRenderIntegrityInternal(GetRoot(), screenRegion, + gfx3DMatrix transform; + ComputeRenderIntegrityInternal(root, screenRegion, lowPrecisionScreenRegion, transform); if (!screenRegion.IsEqual(screenRect)) { @@ -1728,7 +1795,8 @@ LayerManagerOGL::ComputeRenderIntegrity() lowPrecisionIntegrity = GetRegionArea(lowPrecisionScreenRegion) / screenArea; } - return (highPrecisionIntegrity + lowPrecisionIntegrity) / 2.f; + return ((highPrecisionIntegrity * highPrecisionMultiplier) + + (lowPrecisionIntegrity * lowPrecisionMultiplier)) / 2.f; } return 1.f; diff --git a/mobile/android/base/gfx/LayerRenderer.java b/mobile/android/base/gfx/LayerRenderer.java index bcc06ab85010..8c42e32657cd 100644 --- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -598,46 +598,8 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener { Layer rootLayer = mView.getLayerClient().getRoot(); if ((rootLayer != null) && (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) { - // Find out how much of the viewport area is valid - Rect viewport = RectUtils.round(mPageContext.viewport); - Region validRegion = rootLayer.getValidRegion(mPageContext); - - /* restrict the viewport to page bounds so we don't - * count overscroll as checkerboard */ - if (!viewport.intersect(mAbsolutePageRect)) { - /* if the rectangles don't intersect - intersect() doesn't change viewport - so we set it to empty by hand */ - viewport.setEmpty(); - } - validRegion.op(viewport, Region.Op.INTERSECT); - - // Check if we have total checkerboarding (there's visible - // page area and the valid region doesn't intersect with the - // viewport). - int screenArea = viewport.width() * viewport.height(); - float checkerboard = (screenArea > 0 && - validRegion.quickReject(viewport)) ? 1.0f : 0.0f; - - if (screenArea > 0 && checkerboard < 1.0f) { - validRegion.op(viewport, Region.Op.REVERSE_DIFFERENCE); - - // XXX The assumption here is that a Region never has overlapping - // rects. This is true, as evidenced by reading the SkRegion - // source, but is not mentioned in the Android documentation, - // and so is liable to change. - // If it does change, this code will need to be reevaluated. - Rect r = new Rect(); - int checkerboardArea = 0; - for (RegionIterator i = new RegionIterator(validRegion); i.next(r);) { - checkerboardArea += r.width() * r.height(); - } - - checkerboard = checkerboardArea / (float)screenArea; - - // Add any incomplete rendering in the screen area - checkerboard += (1.0 - checkerboard) * (1.0 - GeckoAppShell.computeRenderIntegrity()); - } + // Calculate the incompletely rendered area of the page + float checkerboard = 1.0f - GeckoAppShell.computeRenderIntegrity(); PanningPerfAPI.recordCheckerboard(checkerboard);