Bug 648484, part A: Allow D3D10 layers to render directly to a share-able texture. r=Bas
authorChris Jones <jones.chris.g@gmail.com>
Tue, 09 Aug 2011 12:38:26 -0700
changeset 74140 c83050561980052a41a24386124a30f014d7a776
parent 74139 5478c7ef7debd7a27657d2a2c1420c21e50f2cdc
child 74141 dcd012767e710216dfd79e429437024222f9a0f5
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersBas
bugs648484
milestone8.0a1
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.
  */