Bug 805028 - Add LayerManagerOGL::ComputeRenderIntegrity. r=bgirard
authorChris Lord <chrislord.net@gmail.com>
Thu, 25 Oct 2012 17:23:42 +0100
changeset 111542 221f94d010178ea6900a5f821a75972b40cb2b44
parent 111541 5298adc7096310534bd9572f648a4164326a1078
child 111543 0592d78779d932329b37fc1bbbf67646ca9bba9f
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbgirard
bugs805028
milestone19.0a1
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
gfx/layers/opengl/LayerManagerOGL.h
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1448,10 +1448,92 @@ LayerManagerOGL::CreateDrawTarget(const 
   if (useAcceleration) {
     return Factory::CreateDrawTarget(BACKEND_COREGRAPHICS_ACCELERATED,
                                      aSize, aFormat);
   }
 #endif
   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 */
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -356,16 +356,25 @@ public:
   /**
    * Creates a DrawTarget which is optimized for inter-operating with this
    * layermanager.
    */
   virtual TemporaryRef<mozilla::gfx::DrawTarget>
     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;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -435,16 +444,25 @@ private:
   void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
 
   /**
    * Helper method for Initialize, creates all valid variations of a program
    * and adds them to mPrograms
    */
   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;
   void *mThebesLayerCallbackData;
   gfxMatrix mWorldMatrix;
   nsAutoPtr<FPSState> mFPS;
 
   static bool sDrawFPS;