Bug 539356 - Part 8a - Add END_NO_COMPOSITE to EndTransactionFlags and implement in for all LayerManagers. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 11 Jun 2012 16:44:08 +1200
changeset 97880 f1d43208825c9068efee4bd4ac9a7a13eba0bbe7
parent 97879 4859876972f37b60ed16d8c9ee80a367bc15c953
child 97881 0cd288a3808594737dbf48ffc57608f5c20e384d
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs539356
milestone16.0a1
Bug 539356 - Part 8a - Add END_NO_COMPOSITE to EndTransactionFlags and implement in for all LayerManagers. r=roc
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/ColorLayerD3D9.cpp
gfx/layers/d3d9/ContainerLayerD3D9.cpp
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.h
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
widget/cocoa/nsChildView.mm
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -289,17 +289,18 @@ public:
   typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
                                            gfxContext* aContext,
                                            const nsIntRegion& aRegionToDraw,
                                            const nsIntRegion& aRegionToInvalidate,
                                            void* aCallbackData);
 
   enum EndTransactionFlags {
     END_DEFAULT = 0,
-    END_NO_IMMEDIATE_REDRAW = 1 << 0  // Do not perform the drawing phase
+    END_NO_IMMEDIATE_REDRAW = 1 << 0,  // Do not perform the drawing phase
+    END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
   };
 
   /**
    * Finish the construction phase of the transaction, perform the
    * drawing phase, and end the transaction.
    * During the drawing phase, all ThebesLayers in the tree are
    * drawn in tree order, exactly once each, except for those layers
    * where it is known that the visible region is empty.
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1642,16 +1642,22 @@ BasicLayerManager::EndTransactionInterna
   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   mPhase = PHASE_DRAWING;
 
   Layer* aLayer = GetRoot();
   RenderTraceLayers(aLayer, "FF00");
 
   mTransactionIncomplete = false;
 
+  if (aFlags & END_NO_COMPOSITE) {
+    // TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
+    nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
+    mTarget = new gfxContext(surf);
+  }
+
   if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     nsIntRect clipRect;
     if (HasShadowManager()) {
       // If this has a shadow manager, the clip extents of mTarget are meaningless.
       // So instead just use the root layer's visible region bounds.
       const nsIntRect& bounds = mRoot->GetVisibleRegion().GetBounds();
       gfxRect deviceRect =
           mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
@@ -1671,19 +1677,29 @@ BasicLayerManager::EndTransactionInterna
     if (IsRetained()) {
       nsIntRegion region;
       MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
       if (mUsingDefaultTarget && mDoubleBuffering != BUFFER_NONE) {
         ApplyDoubleBuffering(mRoot, clipRect);
       }
     }
 
-    PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
-    if (mWidget) {
-      FlashWidgetUpdateArea(mTarget);
+    if (aFlags & END_NO_COMPOSITE) {
+      if (IsRetained()) {
+        // Clip the destination out so that we don't draw to it, and
+        // only end up validating ThebesLayers.
+        mTarget->Clip(gfxRect(0, 0, 0, 0));
+        PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
+      }
+      // If we're not retained, then don't composite means do nothing at all.
+    } else {
+      PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
+      if (mWidget) {
+        FlashWidgetUpdateArea(mTarget);
+      }
     }
 
     if (!mTransactionIncomplete) {
       // Clear out target if we have a complete transaction.
       mTarget = nsnull;
     }
   }
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -315,17 +315,17 @@ LayerManagerD3D10::EndTransaction(DrawTh
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
 #ifdef MOZ_LAYERS_HAVE_LOG
     MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
     Log();
 #endif
 
-    Render();
+    Render(aFlags);
     mCurrentCallbackInfo.Callback = nsnull;
     mCurrentCallbackInfo.CallbackData = nsnull;
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   Log();
   MOZ_LAYERS_LOG(("]----- EndTransaction"));
 #endif
@@ -644,20 +644,24 @@ LayerManagerD3D10::EnsureReadbackManager
     return;
   }
 
   mReadbackManager = new ReadbackManagerD3D10();
   attachments->mReadbackManager = mReadbackManager;
 }
 
 void
-LayerManagerD3D10::Render()
+LayerManagerD3D10::Render(EndTransactionFlags aFlags)
 {
   static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
 
+  if (aFlags & END_NO_COMPOSITE) {
+    return;
+  }
+
   SetupPipeline();
 
   float black[] = { 0, 0, 0, 0 };
   device()->ClearRenderTargetView(mRTView, black);
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -172,17 +172,17 @@ public:
   static void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
 private:
   void SetupPipeline();
   void UpdateRenderTarget();
   void VerifyBufferSize();
   void EnsureReadbackManager();
 
-  void Render();
+  void Render(EndTransactionFlags aFlags);
 
   nsRefPtr<ID3D10Device1> mDevice;
 
   nsRefPtr<ID3D10Effect> mEffect;
   nsRefPtr<ID3D10InputLayout> mInputLayout;
   nsRefPtr<ID3D10Buffer> mVertexBuffer;
   nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
 
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -187,16 +187,19 @@ CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 CanvasLayerD3D9::RenderLayer()
 {
   UpdateSurface();
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   if (!mTexture)
     return;
 
   /*
    * We flip the Y axis here, note we can only do this because we are in 
    * CULL_NONE mode!
@@ -356,17 +359,17 @@ Layer*
 ShadowCanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerD3D9::RenderLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 
 } /* namespace layers */
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -14,16 +14,19 @@ ColorLayerD3D9::GetLayer()
   return this;
 }
 
 static void
 RenderColorLayerD3D9(ColorLayer* aLayer, LayerManagerD3D9 *aManager)
 {
   // XXX we might be able to improve performance by using
   // IDirect3DDevice9::Clear
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   aManager->device()->SetVertexShaderConstantF(
     CBvLayerQuad,
     ShaderConstantRect(visibleRect.x,
                        visibleRect.y,
                        visibleRect.width,
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -142,31 +142,34 @@ ContainerRender(Container* aContainer,
   ReadbackProcessor readback;
   readback.BuildUpdates(aContainer);
 
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
   bool useIntermediate = aContainer->UseIntermediateSurface();
 
   aContainer->mSupportsComponentAlphaChildren = false;
   if (useIntermediate) {
-    aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
-    HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
-                                                   D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
-                                                   D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
-                                                   NULL);
-    if (FAILED(hr)) {
-      aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
-                              hr);
-      return;
+    nsRefPtr<IDirect3DSurface9> renderSurface;
+    if (!aManager->CompositingDisabled()) {
+      aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
+      HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
+                                                     D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                                                     D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
+                                                     NULL);
+      if (FAILED(hr)) {
+        aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
+                                hr);
+        return;
+      }
+
+      nsRefPtr<IDirect3DSurface9> renderSurface;
+      renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
+      aManager->device()->SetRenderTarget(0, renderSurface);
     }
 
-    nsRefPtr<IDirect3DSurface9> renderSurface;
-    renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
-    aManager->device()->SetRenderTarget(0, renderSurface);
-
     if (aContainer->mVisibleRegion.GetNumRects() == 1 && 
         (aContainer->GetContentFlags() & aContainer->CONTENT_OPAQUE)) {
       // don't need a background, we're going to paint all opaque stuff
       aContainer->mSupportsComponentAlphaChildren = true;
     } else {
       const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
       gfxMatrix transform;
       // If we have an opaque ancestor layer, then we can be sure that
@@ -177,22 +180,24 @@ ContainerRender(Container* aContainer,
       if (HasOpaqueAncestorLayer(aContainer) &&
           transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
         // Copy background up from below
         RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
         RECT src = dest;
         ::OffsetRect(&src,
                      visibleRect.x + PRInt32(transform.x0),
                      visibleRect.y + PRInt32(transform.y0));
-        hr = aManager->device()->
-          StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        if (!aManager->CompositingDisabled()) {
+          hr = aManager->device()->
+            StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        }
       }
       if (hr == S_OK) {
         aContainer->mSupportsComponentAlphaChildren = true;
-      } else {
+      } else if (!aManager->CompositingDisabled()) {
         aManager->device()->
           Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
       }
     }
 
     aManager->device()->
       GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     renderTargetOffset[0] = (float)visibleRect.x;
@@ -251,17 +256,17 @@ ContainerRender(Container* aContainer,
       static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback);
     } else {
       layerToRender->RenderLayer();
     }
   }
     
   aManager->device()->SetScissorRect(&containerD3D9ClipRect);
 
-  if (useIntermediate) {
+  if (useIntermediate && !aManager->CompositingDisabled()) {
     aManager->device()->SetRenderTarget(0, previousRenderTarget);
     aManager->device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     aManager->device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
 
     aManager->device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(visibleRect.x,
                                                           visibleRect.y,
                                                           visibleRect.width,
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -338,17 +338,17 @@ ImageLayerD3D9::GetTexture(Image *aImage
 
   return data->mTexture;
 }
 
 void
 ImageLayerD3D9::RenderLayer()
 {
   ImageContainer *container = GetContainer();
-  if (!container) {
+  if (!container || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
     return;
@@ -589,16 +589,20 @@ Layer*
 ShadowImageLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerD3D9::RenderLayer()
 {
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   if (mBuffer) {
     mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
   } else if (mYCbCrImage) {
     if (!mYCbCrImage->mBufferSize) {
       return;
     }
 
     if (!mYCbCrImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -144,16 +144,17 @@ LayerManagerD3D9::EndTransaction(DrawThe
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     mCurrentCallbackInfo.Callback = aCallback;
     mCurrentCallbackInfo.CallbackData = aCallbackData;
 
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
     Render();
     /* Clean this out for sanity */
     mCurrentCallbackInfo.Callback = NULL;
     mCurrentCallbackInfo.CallbackData = NULL;
   }
 
   // Clear mTarget, next transaction could have no target
   mTarget = NULL;
@@ -279,16 +280,22 @@ void
 LayerManagerD3D9::Render()
 {
   if (!mSwapChain->PrepareForRendering()) {
     return;
   }
   deviceManager()->SetupRenderState();
 
   SetupPipeline();
+
+  if (CompositingDisabled()) {
+    static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
+    return;
+  }
+
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
   device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
 
   device()->BeginScene();
 
   const nsIntRect *clipRect = mRoot->GetClipRect();
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -174,16 +174,19 @@ public:
   { return gfxASurface::ImageFormatARGB32; }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "D3D9"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /* Default device manager instance */
   static DeviceManagerD3D9 *mDefaultDeviceManager;
 
   /* Device manager instance for this layer manager */
   nsRefPtr<DeviceManagerD3D9> mDeviceManager;
 
   /* Swap chain associated with this layer manager */
@@ -207,16 +210,22 @@ private:
 
   /*
    * Device reset count at last paint. Whenever this changes, we need to
    * do a full layer tree update.
    */
   PRUint32 mDeviceResetCount;
 
   /*
+   * True if we should only be drawing layer contents, not
+   * compositing them to the target.
+   */
+  bool mCompositingDisabled;
+
+  /*
    * Render the current layer tree to the active target.
    */
   void Render();
 
   /*
    * Setup the pipeline.
    */
   void SetupPipeline();
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -231,16 +231,20 @@ ThebesLayerD3D9::RenderThebesLayer(Readb
       return;
     }
 
     DrawRegion(drawRegion, mode, readbackUpdates);
 
     mValidRegion = neededRegion;
   }
 
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   SetShaderTransformAndOpacity();
 
   if (mode == SURFACE_COMPONENT_ALPHA) {
     mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1,
                                GetMaskLayer());
     device()->SetTexture(0, mTexture);
     device()->SetTexture(1, mTextureOnWhite);
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
@@ -649,17 +653,17 @@ bool
 ShadowThebesLayerD3D9::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerD3D9::RenderThebesLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 void
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -189,16 +189,19 @@ CanvasLayerOGL::UpdateSurface()
   }
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
                             const nsIntPoint& aOffset)
 {
   UpdateSurface();
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
@@ -360,16 +363,19 @@ ShadowCanvasLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
 
   ShaderProgramOGL *program =
     mOGLManager->GetProgram(mTexImage->GetShaderProgramType(),
                             GetMaskLayer());
 
 
   gfx3DMatrix effectiveTransform = GetEffectiveTransform();
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -7,16 +7,20 @@
 
 namespace mozilla {
 namespace layers {
 
 static void
 RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
                  const nsIntPoint& aOffset)
 {
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
+
   aManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   /* Multiply color by the layer opacity, as the shader
    * ignores layer opacity and expects a final color to
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -174,22 +174,24 @@ ContainerRender(Container* aContainer,
         mode = LayerManagerOGL::InitModeCopy;
         framebufferRect.x += transform.x0;
         framebufferRect.y += transform.y0;
         aContainer->mSupportsComponentAlphaChildren = true;
       }
     }
 
     aContainer->gl()->PushViewportRect();
-    framebufferRect -= childOffset; 
-    aManager->CreateFBOWithTexture(framebufferRect,
-                                   mode,
-                                   aPreviousFrameBuffer,
-                                   &frameBuffer,
-                                   &containerSurface);
+    framebufferRect -= childOffset;
+    if (!aManager->CompositingDisabled()) {
+      aManager->CreateFBOWithTexture(framebufferRect,
+                                     mode,
+                                     aPreviousFrameBuffer,
+                                     &frameBuffer,
+                                     &containerSurface);
+    }
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
   }
 
@@ -234,55 +236,57 @@ ContainerRender(Container* aContainer,
 #endif
     
     // Restore the viewport
     aContainer->gl()->PopViewportRect();
     nsIntRect viewport = aContainer->gl()->ViewportRect();
     aManager->SetupPipeline(viewport.width, viewport.height,
                             LayerManagerOGL::ApplyWorldTransform);
     aContainer->gl()->PopScissorRect();
-
     aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-    aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    if (!aManager->CompositingDisabled()) {
+      aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
+      aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+      aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
 
-    MaskType maskType = MaskNone;
-    if (aContainer->GetMaskLayer()) {
-      if (!aContainer->GetTransform().CanDraw2D()) {
-        maskType = Mask3d;
-      } else {
-        maskType = Mask2d;
+      MaskType maskType = MaskNone;
+      if (aContainer->GetMaskLayer()) {
+        if (!aContainer->GetTransform().CanDraw2D()) {
+          maskType = Mask3d;
+        } else {
+          maskType = Mask2d;
+        }
       }
-    }
-    ShaderProgramOGL *rgb =
-      aManager->GetFBOLayerProgram(maskType);
+      ShaderProgramOGL *rgb =
+        aManager->GetFBOLayerProgram(maskType);
 
-    rgb->Activate();
-    rgb->SetLayerQuadRect(visibleRect);
-    rgb->SetLayerTransform(transform);
-    rgb->SetLayerOpacity(opacity);
-    rgb->SetRenderOffset(aOffset);
-    rgb->SetTextureUnit(0);
-    rgb->LoadMask(aContainer->GetMaskLayer());
+      rgb->Activate();
+      rgb->SetLayerQuadRect(visibleRect);
+      rgb->SetLayerTransform(transform);
+      rgb->SetLayerOpacity(opacity);
+      rgb->SetRenderOffset(aOffset);
+      rgb->SetTextureUnit(0);
+      rgb->LoadMask(aContainer->GetMaskLayer());
 
-    if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
-      // 2DRect case, get the multiplier right for a sampler2DRect
-      rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
-    }
+      if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
+        // 2DRect case, get the multiplier right for a sampler2DRect
+        rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
+      }
 
-    // Drawing is always flipped, but when copying between surfaces we want to avoid
-    // this. Pass true for the flip parameter to introduce a second flip
-    // that cancels the other one out.
-    aManager->BindAndDrawQuad(rgb, true);
+      // Drawing is always flipped, but when copying between surfaces we want to avoid
+      // this. Pass true for the flip parameter to introduce a second flip
+      // that cancels the other one out.
+      aManager->BindAndDrawQuad(rgb, true);
 
-    // Clean up resources.  This also unbinds the texture.
-    aContainer->gl()->fDeleteTextures(1, &containerSurface);
+      // Clean up resources.  This also unbinds the texture.
+      aContainer->gl()->fDeleteTextures(1, &containerSurface);
+    }
   } else {
     aContainer->gl()->PopScissorRect();
   }
 }
 
 ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
   : ContainerLayer(aManager, NULL)
   , LayerOGL(aManager)
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -181,17 +181,17 @@ ImageLayerOGL::GetLayer()
 }
 
 void
 ImageLayerOGL::RenderLayer(int,
                            const nsIntPoint& aOffset)
 {
   nsRefPtr<ImageContainer> container = GetContainer();
 
-  if (!container)
+  if (!container || mOGLManager->CompositingDisabled())
     return;
 
   mOGLManager->MakeCurrent();
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
@@ -767,16 +767,19 @@ ShadowImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                  const nsIntPoint& aOffset)
 {
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
 
   if (mTexImage) {
     ShaderProgramOGL *colorProgram =
       mOGLManager->GetProgram(mTexImage->GetShaderProgramType(), GetMaskLayer());
 
     colorProgram->Activate();
     colorProgram->SetTextureUnit(0);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -405,16 +405,17 @@ LayerManagerOGL::EndTransaction(DrawTheb
 
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
     mThebesLayerCallback = aCallback;
     mThebesLayerCallbackData = aCallbackData;
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
 
     Render();
 
     mThebesLayerCallback = nsnull;
     mThebesLayerCallbackData = nsnull;
   }
 
   mTarget = NULL;
@@ -757,16 +758,23 @@ LayerManagerOGL::Render()
   if (clipRect) {
     nsIntRect r = *clipRect;
     WorldTransformRect(r);
     mGLContext->fScissor(r.x, r.y, r.width, r.height);
   } else {
     mGLContext->fScissor(0, 0, width, height);
   }
 
+  if (CompositingDisabled()) {
+    RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
+                             nsIntPoint(0, 0));
+    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+    return;
+  }
+
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
 
   // If the Java compositor is being used, this clear will be done in
   // DrawWindowUnderlay. Make sure the bits used here match up with those used
   // in mobile/android/base/gfx/LayerRenderer.java
 #ifndef MOZ_JAVA_COMPOSITOR
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -345,16 +345,19 @@ public:
   gfxMatrix& GetWorldTransform(void);
   void WorldTransformRect(nsIntRect& aRect);
 
   /**
    * Set the size of the surface we're rendering to.
    */
   void SetSurfaceSize(int width, int height);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -386,16 +389,17 @@ private:
    *  flipped and unflipped textures */
   GLuint mQuadVBO;
 
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
 
   /** Misc */
   bool mHasBGRA;
+  bool mCompositingDisabled;
 
   /**
    * When rendering to an EGL surface (e.g. on Android), we rely on being told
    * about size changes (via SetSurfaceSize) rather than pulling this information
    * from the widget, since the widget's information can lag behind.
    */
   bool mIsRenderingToEGLSurface;
 
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -78,16 +78,18 @@ public:
 
   enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
   virtual PaintState BeginPaint(ContentType aContentType,
                                 PRUint32 aFlags) = 0;
 
   void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
                 PRUint32 aFlags);
 
+  void EndUpdate();
+
   nsIntSize GetSize() {
     if (mTexImage)
       return mTexImage->GetSize();
     return nsIntSize(0, 0);
   }
 
   bool Initialised() { return mInitialised; }
 
@@ -98,33 +100,38 @@ protected:
 
   ThebesLayer* mLayer;
   LayerOGL* mOGLLayer;
   nsRefPtr<TextureImage> mTexImage;
   nsRefPtr<TextureImage> mTexImageOnWhite;
   bool mInitialised;
 };
 
+void ThebesLayerBufferOGL::EndUpdate()
+{
+  if (mTexImage && mTexImage->InUpdate()) {
+    mTexImage->EndUpdate();
+  }
+
+  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
+    mTexImageOnWhite->EndUpdate();
+  }
+}
+
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
                                LayerManagerOGL* aManager,
                                PRUint32 aFlags)
 {
   NS_ASSERTION(Initialised(), "RenderTo with uninitialised buffer!");
 
   if (!mTexImage || !Initialised())
     return;
 
-  if (mTexImage->InUpdate()) {
-    mTexImage->EndUpdate();
-  }
-
-  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
-    mTexImageOnWhite->EndUpdate();
-  }
+  EndUpdate();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = 
       gl()->GetTexImage(mTexImage->GetTextureID(), false, mTexImage->GetShaderProgramType());
     
     WriteSnapshotToDumpFile(mLayer, surf);
   }
@@ -828,16 +835,21 @@ ThebesLayerOGL::RenderLayer(int aPreviou
       // here (OR doesn't automatically simplify to the simplest possible
       // representation of a region.)
       nsIntRegion tmp;
       tmp.Or(mVisibleRegion, state.mRegionToDraw);
       mValidRegion.Or(mValidRegion, tmp);
     }
   }
 
+  if (mOGLManager->CompositingDisabled()) {
+    mBuffer->EndUpdate();
+    return;
+  }
+
   // Drawing thebes layers can change the current context, reset it.
   gl()->MakeCurrent();
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
   mBuffer->RenderTo(aOffset, mOGLManager, flags);
 }
 
 Layer*
@@ -1258,17 +1270,17 @@ ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
-  if (!mBuffer) {
+  if (!mBuffer || mOGLManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
 
   if (ShouldDoubleBuffer()) {
     // Find out what part of the screen this layer intersects with
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2546,16 +2546,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
     LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(layerManager);
     manager->SetClippingRegion(paintEvent.region);
     glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
 
     if (!mGLContext) {
       [self setGLContext:glContext];
     }
 
+    [glContext setView:self];
+    [glContext update];
+
     mGeckoChild->DispatchWindowEvent(paintEvent);
 
     // Force OpenGL to refresh the very first time we draw. This works around a
     // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
     if (!mDidForceRefreshOpenGL) {
       [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
       mDidForceRefreshOpenGL = YES;
     }