From 0206c993d626402e4e98e8451fcf3731203385ea Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Thu, 25 Oct 2012 17:23:42 +0100 Subject: [PATCH] Bug 805028 - Add LayerManagerOGL::ComputeRenderIntegrity. r=bgirard Add a function to LayerManagerOGL that can compute how much of the last rendered area was incomplete (i.e. is pending update when progressive tile drawing is enabled). --- gfx/layers/opengl/LayerManagerOGL.cpp | 82 +++++++++++++++++++++++++++ gfx/layers/opengl/LayerManagerOGL.h | 18 ++++++ 2 files changed, 100 insertions(+) diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index ad25c76f3750..d8ce38e4a9a5 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -1453,5 +1453,87 @@ LayerManagerOGL::CreateDrawTarget(const IntSize &aSize, return LayerManager::CreateDrawTarget(aSize, aFormat); } +/* static */ void +LayerManagerOGL::ComputeRenderIntegrityInternal(Layer* aLayer, + nsIntRegion& aScreenRegion, + const gfx3DMatrix& aTransform) +{ + if (aScreenRegion.IsEmpty() || aLayer->GetOpacity() <= 0.f) { + return; + } + + // If the layer's a container, recurse into all of its children + ContainerLayer* container = aLayer->AsContainerLayer(); + if (container) { + // Accumulate the transform of intermediate surfaces + gfx3DMatrix transform = aTransform; + if (container->UseIntermediateSurface()) { + transform = aLayer->GetEffectiveTransform(); + transform.PreMultiply(aTransform); + } + for (Layer* child = aLayer->GetFirstChild(); child; + child = child->GetNextSibling()) { + ComputeRenderIntegrityInternal(child, aScreenRegion, transform); + } + return; + } + + // Only thebes layers can be incomplete + ThebesLayer* thebesLayer = aLayer->AsThebesLayer(); + if (!thebesLayer) { + return; + } + + // See if there's any incomplete rendering + nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion(); + incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion()); + + if (!incompleteRegion.IsEmpty()) { + // Calculate the transform to get between screen and layer space + gfx3DMatrix transformToScreen = aLayer->GetEffectiveTransform(); + transformToScreen.PreMultiply(aTransform); + + // For each rect in the region, find out its bounds in screen space and + // subtract it from the screen region. + nsIntRegionRectIterator it(incompleteRegion); + while (const nsIntRect* rect = it.Next()) { + gfxRect incompleteRect = transformToScreen.TransformBounds(gfxRect(*rect)); + aScreenRegion.Sub(aScreenRegion, nsIntRect(incompleteRect.x, + incompleteRect.y, + incompleteRect.width, + incompleteRect.height)); + } + } +} + +float +LayerManagerOGL::ComputeRenderIntegrity() +{ + // We only ever have incomplete rendering when progressive tiles are enabled. + if (!gfxPlatform::UseProgressiveTilePainting() || !GetRoot()) { + return 1.f; + } + + // XXX We assume that mWidgetSize represents the 'screen' area. + gfx3DMatrix transform; + nsIntRect screenRect(0, 0, mWidgetSize.width, mWidgetSize.height); + nsIntRegion screenRegion(screenRect); + ComputeRenderIntegrityInternal(GetRoot(), screenRegion, transform); + + if (!screenRegion.IsEqual(screenRect)) { + // Calculate the area of the region. All rects in an nsRegion are + // non-overlapping. + int area = 0; + nsIntRegionRectIterator it(screenRegion); + while (const nsIntRect* rect = it.Next()) { + area += rect->width * rect->height; + } + + return area / (float)(screenRect.width * screenRect.height); + } + + return 1.f; +} + } /* layers */ } /* mozilla */ diff --git a/gfx/layers/opengl/LayerManagerOGL.h b/gfx/layers/opengl/LayerManagerOGL.h index f5fa2a14cd33..843367ee9fa5 100644 --- a/gfx/layers/opengl/LayerManagerOGL.h +++ b/gfx/layers/opengl/LayerManagerOGL.h @@ -361,6 +361,15 @@ public: CreateDrawTarget(const mozilla::gfx::IntSize &aSize, mozilla::gfx::SurfaceFormat aFormat); + /** + * Calculates the 'completeness' of the rendering that intersected with the + * screen on the last render. This is only useful when progressive tile + * drawing is enabled, otherwise this will always return 1.0. + * This function's expense scales with the size of the layer tree and the + * complexity of individual layers' valid regions. + */ + float ComputeRenderIntegrity(); + private: /** Widget associated with this layer manager */ nsIWidget *mWidget; @@ -440,6 +449,15 @@ private: */ void AddPrograms(gl::ShaderProgramType aType); + /** + * Recursive helper method for use by ComputeRenderIntegrity. Subtracts + * any incomplete rendering on aLayer from aScreenRegion. aTransform is the + * accumulated transform of intermediate surfaces beneath aLayer. + */ + static void ComputeRenderIntegrityInternal(Layer* aLayer, + nsIntRegion& aScreenRegion, + const gfx3DMatrix& aTransform); + /* Thebes layer callbacks; valid at the end of a transaciton, * while rendering */ DrawThebesLayerCallback mThebesLayerCallback;