Bug 612846 - Part 5: Make ContainerLayerD3D10 support component alpha. r=jrmuizel a=blocking-betan
authorBas Schouten <bschouten@mozilla.com>
Fri, 28 Jan 2011 06:34:33 +0100
changeset 61474 8bb432a920fe2f5ac88dda2ab5e0c310d7dae3fc
parent 61473 b064de51203d809e3ebfa29c61a1fb2943fa355c
child 61475 244738bdb2483eec6257720d4b802c70f6258bd1
push idunknown
push userunknown
push dateunknown
reviewersjrmuizel, blocking-betan
bugs612846
milestone2.0b11pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 612846 - Part 5: Make ContainerLayerD3D10 support component alpha. r=jrmuizel a=blocking-betan
gfx/layers/d3d10/ContainerLayerD3D10.cpp
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -149,16 +149,26 @@ static inline LayerD3D10*
 GetNextSiblingD3D10(LayerD3D10* aLayer)
 {
    Layer* layer = aLayer->GetLayer()->GetNextSibling();
    return layer ? static_cast<LayerD3D10*>(layer->
                                            ImplData())
                 : nsnull;
 }
 
+static PRBool
+HasOpaqueAncestorLayer(Layer* aLayer)
+{
+  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
+    if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
+      return PR_TRUE;
+  }
+  return PR_FALSE;
+}
+
 void
 ContainerLayerD3D10::RenderLayer()
 {
   float renderTargetOffset[] = { 0, 0 };
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
   float opacity = GetEffectiveOpacity();
   PRBool useIntermediate = UseIntermediateSurface();
@@ -183,37 +193,66 @@ ContainerLayerD3D10::RenderLayer()
     desc.Height = visibleRect.height;
     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
     desc.SampleDesc.Count = 1;
     desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
     device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture));
     
     device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView));
 
-    float black[] = { 0, 0, 0, 0};
-    device()->ClearRenderTargetView(rtView, black);
+    effect()->GetVariableByName("vRenderTargetOffset")->
+      GetRawValue(previousRenderTargetOffset, 0, 8);
+
+    if (mVisibleRegion.GetNumRects() != 1 || !(GetContentFlags() & CONTENT_OPAQUE)) {
+      const gfx3DMatrix& transform3D = GetEffectiveTransform();
+      gfxMatrix transform;
+      // If we have an opaque ancestor layer, then we can be sure that
+      // all the pixels we draw into are either opaque already or will be
+      // covered by something opaque. Otherwise copying up the background is
+      // not safe.
+      if (mSupportsComponentAlphaChildren) {
+        PRBool is2d = transform3D.Is2D(&transform);
+        NS_ASSERTION(is2d, "Transform should be 2d when mSupportsComponentAlphaChildren.");
+
+        // Copy background up from below. This applies any 2D transform that is
+        // applied to use relative to our parent, and compensates for the offset
+        // that was applied on our parent's rendering.
+        D3D10_BOX srcBox;
+        srcBox.left = visibleRect.x + PRInt32(transform.x0) - PRInt32(previousRenderTargetOffset[0]);
+        srcBox.top = visibleRect.y + PRInt32(transform.y0) - PRInt32(previousRenderTargetOffset[1]);
+        srcBox.right = srcBox.left + visibleRect.width;
+        srcBox.bottom = srcBox.top + visibleRect.height;
+        srcBox.back = 1;
+        srcBox.front = 0;
+
+        nsRefPtr<ID3D10Resource> srcResource;
+        previousRTView->GetResource(getter_AddRefs(srcResource));
+
+        device()->CopySubresourceRegion(renderTexture, 0,
+                                        0, 0, 0,
+                                        srcResource, 0,
+                                        &srcBox);
+      } else {
+        float black[] = { 0, 0, 0, 0};
+        device()->ClearRenderTargetView(rtView, black);
+      }
+    }
 
     ID3D10RenderTargetView *rtViewPtr = rtView;
     device()->OMSetRenderTargets(1, &rtViewPtr, NULL);
 
-    effect()->GetVariableByName("vRenderTargetOffset")->
-      GetRawValue(previousRenderTargetOffset, 0, 8);
-
     renderTargetOffset[0] = (float)visibleRect.x;
     renderTargetOffset[1] = (float)visibleRect.y;
     effect()->GetVariableByName("vRenderTargetOffset")->
       SetRawValue(renderTargetOffset, 0, 8);
 
     previousViewportSize = mD3DManager->GetViewport();
     mD3DManager->SetViewport(nsIntSize(visibleRect.Size()));
   } else {
-#ifdef DEBUG
-    PRBool is2d =
-#endif
-    GetEffectiveTransform().Is2D(&contTransform);
+    PRBool is2d = GetEffectiveTransform().Is2D(&contTransform);
     NS_ASSERTION(is2d, "Transform must be 2D");
   }
 
   /*
    * Render this container's contents.
    */
   for (LayerD3D10* layerToRender = GetFirstChildD3D10();
        layerToRender != nsnull;
@@ -329,16 +368,41 @@ ContainerLayerD3D10::LayerManagerDestroy
     GetFirstChildD3D10()->LayerManagerDestroyed();
     RemoveChild(mFirstChild);
   }
 }
 
 void
 ContainerLayerD3D10::Validate()
 {
+  nsIntRect visibleRect = mVisibleRegion.GetBounds();
+
+  mSupportsComponentAlphaChildren = PR_FALSE;
+
+  if (UseIntermediateSurface()) {
+    const gfx3DMatrix& transform3D = GetEffectiveTransform();
+    gfxMatrix transform;
+
+    if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) {
+      // don't need a background, we're going to paint all opaque stuff
+      mSupportsComponentAlphaChildren = PR_TRUE;
+    } else {
+      if (HasOpaqueAncestorLayer(this) &&
+          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation() &&
+          GetParent()->GetEffectiveVisibleRegion().GetBounds().Contains(visibleRect))
+      {
+        // In this case we can copy up the background. See RenderLayer.
+        mSupportsComponentAlphaChildren = PR_TRUE;
+      }
+    }
+  } else {
+    mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) ||
+        (mParent && mParent->SupportsComponentAlphaChildren());
+  }
+
   Layer *layer = GetFirstChild();
   while (layer) {
     static_cast<LayerD3D10*>(layer->ImplData())->Validate();
     layer = layer->GetNextSibling();
   }
 }
 
 } /* layers */