Bug 648484, part A: Allow D3D10 layers to render directly to a share-able texture. r=Bas
authorChris Jones <jones.chris.g@gmail.com>
Wed, 13 Jul 2011 22:43:43 -0700
changeset 72811 098a1ccb8757eedf0caec48fd323b9ed5ea0ea4b
parent 72810 b53e2d275d15437600ba1f373b98c3af99bf818f
child 72812 53225816d90a4be383a205a3c09a45e5f1c5d9e4
push id20772
push usereakhgari@mozilla.com
push dateThu, 14 Jul 2011 16:20:50 +0000
treeherdermozilla-central@89b5fccb0514 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs648484
milestone8.0a1
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 648484, part A: Allow D3D10 layers to render directly to a share-able texture. r=Bas
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.h
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -30,16 +30,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include <algorithm>
+
 #include "LayerManagerD3D10.h"
 #include "LayerManagerD3D10Effect.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxD2DSurface.h"
 #include "gfxFailure.h"
 #include "cairo-win32.h"
 #include "dxgi.h"
 
@@ -49,16 +51,17 @@
 #include "CanvasLayerD3D10.h"
 #include "ReadbackLayerD3D10.h"
 #include "ImageLayerD3D10.h"
 
 #include "../d3d9/Nv3DVUtils.h"
 
 #include "gfxCrashReporterUtils.h"
 
+using namespace std;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
     void *pData,
     SIZE_T DataLength,
@@ -222,16 +225,21 @@ LayerManagerD3D10::Initialize()
 
     attachments->mVertexBuffer = mVertexBuffer;
   } else {
     mEffect = attachments->mEffect;
     mVertexBuffer = attachments->mVertexBuffer;
     mInputLayout = attachments->mInputLayout;
   }
 
+  if (HasShadowManager()) {
+    reporter.SetSuccessful();
+    return true;
+  }
+
   nsRefPtr<IDXGIDevice> dxgiDevice;
   nsRefPtr<IDXGIAdapter> dxgiAdapter;
   nsRefPtr<IDXGIFactory> dxgiFactory;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
   dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
 
   dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
@@ -569,49 +577,82 @@ LayerManagerD3D10::UpdateRenderTarget()
   if (mRTView) {
     return;
   }
 
   HRESULT hr;
 
   nsRefPtr<ID3D10Texture2D> backBuf;
   
-  hr = mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
-  if (FAILED(hr)) {
-    return;
+  if (mSwapChain) {
+    hr = mSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)backBuf.StartAssignment());
+    if (FAILED(hr)) {
+      return;
+    }
+  } else {
+    backBuf = mBackBuffer;
   }
   
   mDevice->CreateRenderTargetView(backBuf, NULL, getter_AddRefs(mRTView));
 }
 
 void
 LayerManagerD3D10::VerifyBufferSize()
 {
-  DXGI_SWAP_CHAIN_DESC swapDesc;
-  mSwapChain->GetDesc(&swapDesc);
-
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
-  if (swapDesc.BufferDesc.Width == rect.width &&
-      swapDesc.BufferDesc.Height == rect.height) {
-    return;
-  }
+  HRESULT hr;
+  if (mSwapChain) {
+    DXGI_SWAP_CHAIN_DESC swapDesc;
+    mSwapChain->GetDesc(&swapDesc);
+
+    if (swapDesc.BufferDesc.Width == rect.width &&
+        swapDesc.BufferDesc.Height == rect.height) {
+      return;
+    }
 
-  mRTView = nsnull;
-  if (gfxWindowsPlatform::IsOptimus()) {
-    mSwapChain->ResizeBuffers(1, rect.width, rect.height,
-                              DXGI_FORMAT_B8G8R8A8_UNORM,
-                              0);
+    mRTView = nsnull;
+    if (gfxWindowsPlatform::IsOptimus()) {
+      mSwapChain->ResizeBuffers(1, rect.width, rect.height,
+                                DXGI_FORMAT_B8G8R8A8_UNORM,
+                                0);
+    } else {
+      mSwapChain->ResizeBuffers(1, rect.width, rect.height,
+                                DXGI_FORMAT_B8G8R8A8_UNORM,
+                                DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
+    }
   } else {
-    mSwapChain->ResizeBuffers(1, rect.width, rect.height,
-                              DXGI_FORMAT_B8G8R8A8_UNORM,
-                              DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
+    D3D10_TEXTURE2D_DESC oldDesc;    
+    if (mBackBuffer) {
+        mBackBuffer->GetDesc(&oldDesc);
+    } else {
+        oldDesc.Width = oldDesc.Height = 0;
+    }
+    if (oldDesc.Width == rect.width &&
+        oldDesc.Height == rect.height) {
+      return;
+    }
+
+    CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
+                               rect.width, rect.height, 1, 1);
+    desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
+    desc.MiscFlags = D3D10_RESOURCE_MISC_SHARED
+                     // FIXME/bug 662109: synchronize using KeyedMutex
+                     /*D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX*/;
+    hr = device()->CreateTexture2D(&desc, nsnull, getter_AddRefs(mBackBuffer));
+    if (FAILED(hr)) {
+        ReportFailure(nsDependentCString("Failed to create shared texture"),
+                      hr);
+        NS_RUNTIMEABORT("Failed to create back buffer");
+    }
+
+    // XXX resize texture?
+    mRTView = nsnull;
   }
-
 }
 
 void
 LayerManagerD3D10::EnsureReadbackManager()
 {
   if (mReadbackManager) {
     return;
   }
@@ -661,16 +702,19 @@ LayerManagerD3D10::Render()
     r.bottom = rect.height;
   }
   device()->RSSetScissorRects(1, &r);
 
   static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer();
 
   if (mTarget) {
     PaintToTarget();
+  } else if (mBackBuffer) {
+    swap(mBackBuffer, mRemoteFrontBuffer);
+    mRTView = nsnull;
   } else {
     mSwapChain->Present(0, 0);
   }
 }
 
 void
 LayerManagerD3D10::PaintToTarget()
 {
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -222,16 +222,33 @@ private:
   nsAutoPtr<Nv3DVUtils> mNv3DVUtils; 
 
   /*
    * Context target, NULL when drawing directly to our swap chain.
    */
   nsRefPtr<gfxContext> mTarget;
 
   /*
+   * We use a double-buffered "window surface" to display our content
+   * in the compositor process, if we're remote.  The textures act
+   * like the backing store for an OS window --- we render the layer
+   * tree into the back texture and send it to the compositor, then
+   * swap back/front textures.  This means, obviously, that we've lost
+   * all layer tree information after rendering.
+   *
+   * The remote front buffer is the texture currently being displayed
+   * by chrome.  We keep a reference to it to simplify resource
+   * management; if we didn't, then there can be periods during IPC
+   * transport when neither process holds a "real" ref.  That's
+   * solvable but not worth the complexity.
+   */
+  nsRefPtr<ID3D10Texture2D> mBackBuffer;
+  nsRefPtr<ID3D10Texture2D> mRemoteFrontBuffer;
+
+  /*
    * Copies the content of our backbuffer to the set transaction target.
    */
   void PaintToTarget();
 };
 
 /*
  * General information and tree management for OGL layers.
  */