Bug 612846 - Part 5 - Make ContainerLayerD3D10 support component alpha. r=Bas a=blocking2.0 try: -b do -p win32 -u all -t all
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 20 Jan 2011 15:47:39 +1300
changeset 60902 89c2c85429fb06cc35c7086ff322b19b2a49ffab
parent 60901 aeb9104f153422cea5074bb7bbfe6139fb03d01d
child 60903 59aac0287d1c9cde44ac6228e0ce3f6363edb6d1
push idunknown
push userunknown
push dateunknown
reviewersBas, blocking2
bugs612846
milestone2.0b10pre
Bug 612846 - Part 5 - Make ContainerLayerD3D10 support component alpha. r=Bas a=blocking2.0 try: -b do -p win32 -u all -t all
gfx/layers/d3d10/ContainerLayerD3D10.cpp
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -148,16 +148,26 @@ ContainerLayerD3D10::GetFirstChildD3D10(
 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();
@@ -166,16 +176,17 @@ ContainerLayerD3D10::RenderLayer()
   nsRefPtr<ID3D10RenderTargetView> previousRTView;
   nsRefPtr<ID3D10Texture2D> renderTexture;
   nsRefPtr<ID3D10RenderTargetView> rtView;
   float previousRenderTargetOffset[2];
   nsIntSize previousViewportSize;
 
   gfx3DMatrix oldViewMatrix;
 
+  mSupportsComponentAlphaChildren = PR_FALSE;
   gfxMatrix contTransform;
   if (useIntermediate) {
     device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), NULL);
  
     D3D10_TEXTURE2D_DESC desc;
     memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC));
     desc.ArraySize = 1;
     desc.MipLevels = 1;
@@ -183,38 +194,76 @@ 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)) {
+      // don't need a background, we're going to paint all opaque stuff
+      mSupportsComponentAlphaChildren = PR_TRUE;
+    } else {
+      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 (HasOpaqueAncestorLayer(this) &&
+          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation() &&
+          GetParent()->GetEffectiveVisibleRegion().GetBounds().Contains(visibleRect)) {
+        // Copy background up from below
+        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);
+
+        mSupportsComponentAlphaChildren = PR_TRUE;
+      } 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);
     NS_ASSERTION(is2d, "Transform must be 2D");
+
+    mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) ||
+        (mParent && mParent->SupportsComponentAlphaChildren());
   }
 
   /*
    * Render this container's contents.
    */
   for (LayerD3D10* layerToRender = GetFirstChildD3D10();
        layerToRender != nsnull;
        layerToRender = GetNextSiblingD3D10(layerToRender)) {