Bug 1046550 - Part 3: Use Direct2D 1.1 when preffed on. r=bas
authorMatt Woodrow <mroodrow@mozilla.com>
Sun, 14 Sep 2014 23:51:27 +0200
changeset 205250 7b9201731195c5391405de8d9f52b370a34a4ba0
parent 205249 20e97c8496e46d042b65c423fa2bb577cd6703e2
child 205251 e195dda5f23aeb51efd6272b8f73253899850c99
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbas
bugs1046550
milestone35.0a1
Bug 1046550 - Part 3: Use Direct2D 1.1 when preffed on. r=bas
gfx/layers/d3d11/TextureD3D11.cpp
gfx/layers/d3d11/TextureD3D11.h
gfx/layers/moz.build
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPrefs.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/moz.build
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -6,16 +6,17 @@
 #include "TextureD3D11.h"
 #include "CompositorD3D11.h"
 #include "gfxContext.h"
 #include "Effects.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxD2DSurface.h"
 #include "gfx2DGlue.h"
+#include "gfxPrefs.h"
 #include "ReadbackManagerD3D11.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
@@ -167,30 +168,42 @@ TextureClientD3D11::TextureClientD3D11(g
   , mFormat(aFormat)
   , mIsLocked(false)
   , mNeedsClear(false)
   , mNeedsClearWhite(false)
 {}
 
 TextureClientD3D11::~TextureClientD3D11()
 {
-  if (mTexture && mActor) {
-    KeepUntilFullDeallocation(new TKeepAlive<ID3D10Texture2D>(mTexture));
+  if (mActor) {
+    if (mTexture) {
+      KeepUntilFullDeallocation(new TKeepAlive<ID3D10Texture2D>(mTexture10));
+    } else if (mTexture10) {
+      KeepUntilFullDeallocation(new TKeepAlive<ID3D11Texture2D>(mTexture));
+    }
   }
 #ifdef DEBUG
   // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
   // when it calls EndDraw. This EndDraw should not execute anything so it
   // shouldn't -really- need the lock but the debug layer chokes on this.
   if (mDrawTarget) {
     MOZ_ASSERT(!mIsLocked);
-    MOZ_ASSERT(mTexture);
+    MOZ_ASSERT(mTexture || mTexture10);
     MOZ_ASSERT(mDrawTarget->refCount() == 1);
-    LockD3DTexture(mTexture.get());
+    if (mTexture) {
+      LockD3DTexture(mTexture.get());
+    } else {
+      LockD3DTexture(mTexture10.get());
+    }
     mDrawTarget = nullptr;
-    UnlockD3DTexture(mTexture.get());
+    if (mTexture) {
+      UnlockD3DTexture(mTexture.get());
+    } else {
+      UnlockD3DTexture(mTexture10.get());
+    }
   }
 #endif
 }
 
 TemporaryRef<TextureClient>
 TextureClientD3D11::CreateSimilar(TextureFlags aFlags,
                                   TextureAllocationFlags aAllocFlags) const
 {
@@ -201,22 +214,28 @@ TextureClientD3D11::CreateSimilar(Textur
   }
 
   return tex;
 }
 
 bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
-  if (!mTexture) {
+  if (!IsAllocated()) {
     return false;
   }
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
 
-  mIsLocked = LockD3DTexture(mTexture.get());
+  if (mTexture) {
+    MOZ_ASSERT(!mTexture10);
+    mIsLocked = LockD3DTexture(mTexture.get());
+  } else {
+    MOZ_ASSERT(!mTexture);
+    mIsLocked = LockD3DTexture(mTexture10.get());
+  }
   if (!mIsLocked) {
     return false;
   }
 
   // Make sure that successful write-lock means we will have a DrawTarget to
   // write into.
   if (aMode & OpenMode::OPEN_WRITE) {
     mDrawTarget = BorrowDrawTarget();
@@ -249,75 +268,104 @@ TextureClientD3D11::Unlock()
     // see the comment on TextureClient::BorrowDrawTarget.
     // This DrawTarget is internal to the TextureClient and is only exposed to the
     // outside world between Lock() and Unlock(). This assertion checks that no outside
     // reference remains by the time Unlock() is called.
     MOZ_ASSERT(mDrawTarget->refCount() == 1);
     mDrawTarget->Flush();
   }
 
-  if (mReadbackSink) {
+  if (mReadbackSink && mTexture10) {
     ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
 
     D3D10_TEXTURE2D_DESC desc;
-    mTexture->GetDesc(&desc);
+    mTexture10->GetDesc(&desc);
     desc.BindFlags = 0;
     desc.Usage = D3D10_USAGE_STAGING;
     desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
     desc.MiscFlags = 0;
 
     RefPtr<ID3D10Texture2D> tex;
     HRESULT hr = device->CreateTexture2D(&desc, nullptr, byRef(tex));
 
     if (SUCCEEDED(hr)) {
-      device->CopyResource(tex, mTexture);
+      device->CopyResource(tex, mTexture10);
 
       gfxWindowsPlatform::GetPlatform()->GetReadbackManager()->PostTask(tex, mReadbackSink);
     } else {
       mReadbackSink->ProcessReadback(nullptr);
     }
   }
 
   // The DrawTarget is created only once, and is only usable between calls
   // to Lock and Unlock.
-  UnlockD3DTexture(mTexture.get());
+  if (mTexture) {
+    UnlockD3DTexture(mTexture.get());
+  } else {
+    UnlockD3DTexture(mTexture10.get());
+  }
   mIsLocked = false;
 }
 
 DrawTarget*
 TextureClientD3D11::BorrowDrawTarget()
 {
   MOZ_ASSERT(mIsLocked, "Calling TextureClient::BorrowDrawTarget without locking :(");
 
-  if (!mTexture) {
+  if (!mTexture && !mTexture10) {
     return nullptr;
   }
 
   if (mDrawTarget) {
     return mDrawTarget;
   }
 
   // This may return a null DrawTarget
-  mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
+#if USE_D2D1_1
+  if (mTexture) {
+    mDrawTarget = Factory::CreateDrawTargetForD3D11Texture(mTexture, mFormat);
+  } else
+#endif
+  {
+    MOZ_ASSERT(mTexture10);
+    mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture10, mFormat);
+  }
   return mDrawTarget;
 }
 
 bool
 TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
 {
   mSize = aSize;
-  ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
+  HRESULT hr;
+#ifdef USE_D2D1_1
+  ID3D11Device* d3d11device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
+
+  if (gfxPrefs::Direct2DUse1_1() && d3d11device) {
+
+    CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
+                                  aSize.width, aSize.height, 1, 1,
+                                  D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
+
+    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
-  CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
-                                aSize.width, aSize.height, 1, 1,
-                                D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
+    hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
+  } else
+#endif
+  {
+    ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
 
-  newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+    CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
+      aSize.width, aSize.height, 1, 1,
+      D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
 
-  HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
+    newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+
+    hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture10));
+  }
 
   if (FAILED(hr)) {
     LOGD3D11("Error creating texture for client!");
     return false;
   }
 
   // Defer clearing to the next time we lock to avoid an extra (expensive) lock.
   mNeedsClear = aFlags & ALLOC_CLEAR_BUFFER;
@@ -327,19 +375,23 @@ TextureClientD3D11::AllocateForSurface(g
 }
 
 bool
 TextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   if (!IsAllocated()) {
     return false;
   }
+  RefPtr<IDXGIResource> resource;
+  if (mTexture) {
+    mTexture->QueryInterface((IDXGIResource**)byRef(resource));
+  } else {
+    mTexture10->QueryInterface((IDXGIResource**)byRef(resource));
+  }
 
-  RefPtr<IDXGIResource> resource;
-  mTexture->QueryInterface((IDXGIResource**)byRef(resource));
   HANDLE sharedHandle;
   HRESULT hr = resource->GetSharedHandle(&sharedHandle);
 
   if (FAILED(hr)) {
     LOGD3D11("Error getting shared handle for texture.");
     return false;
   }
 
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -29,17 +29,17 @@ class TextureClientD3D11 : public Textur
 {
 public:
   TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags);
 
   virtual ~TextureClientD3D11();
 
   // TextureClient
 
-  virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mTexture; }
+  virtual bool IsAllocated() const MOZ_OVERRIDE { return mTexture || mTexture10; }
 
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
 
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
@@ -60,17 +60,18 @@ public:
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
   virtual TemporaryRef<TextureClient>
   CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const MOZ_OVERRIDE;
 
 protected:
   gfx::IntSize mSize;
-  RefPtr<ID3D10Texture2D> mTexture;
+  RefPtr<ID3D10Texture2D> mTexture10;
+  RefPtr<ID3D11Texture2D> mTexture;
   RefPtr<gfx::DrawTarget> mDrawTarget;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
   bool mNeedsClear;
   bool mNeedsClearWhite;
 };
 
 /**
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -93,17 +93,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
             'd3d10/ReadbackManagerD3D10.cpp',
             'd3d10/ThebesLayerD3D10.cpp',
             'd3d11/TextureD3D11.cpp',
             'ipc/ShadowLayerUtilsD3D10.cpp',
         ]
         SOURCES += [
             'd3d11/CompositorD3D11.cpp',
             'd3d11/ReadbackManagerD3D11.cpp',
-        ]
+        ]         
+        if CONFIG['MOZ_ENABLE_DIRECT2D1_1']:
+            DEFINES['USE_D2D1_1'] = True
 
 EXPORTS.gfxipc += [
     'ipc/ShadowLayerUtils.h',
 ]
 
 EXPORTS.mozilla.layers += [
     'apz/public/GeckoContentController.h',
     # exporting things from apz/src is temporary until we extract a
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -988,16 +988,18 @@ gfxPlatform::CreateDrawTargetForData(uns
 gfxPlatform::BackendTypeForName(const nsCString& aName)
 {
   if (aName.EqualsLiteral("cairo"))
     return BackendType::CAIRO;
   if (aName.EqualsLiteral("skia"))
     return BackendType::SKIA;
   if (aName.EqualsLiteral("direct2d"))
     return BackendType::DIRECT2D;
+  if (aName.EqualsLiteral("direct2d1.1"))
+    return BackendType::DIRECT2D1_1;
   if (aName.EqualsLiteral("cg"))
     return BackendType::COREGRAPHICS;
   return BackendType::NONE;
 }
 
 nsresult
 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -187,16 +187,17 @@ private:
 
   DECL_GFX_PREF(Live, "gfx.color_management.enablev4",         CMSEnableV4, bool, false);
   DECL_GFX_PREF(Live, "gfx.color_management.mode",             CMSMode, int32_t,-1);
   // The zero default here should match QCMS_INTENT_DEFAULT from qcms.h
   DECL_GFX_PREF(Live, "gfx.color_management.rendering_intent", CMSRenderingIntent, int32_t, 0);
 
   DECL_GFX_PREF(Once, "gfx.direct2d.disabled",                 Direct2DDisabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled",            Direct2DForceEnabled, bool, false);
+  DECL_GFX_PREF(Live, "gfx.direct2d.use1_1",                   Direct2DUse1_1, bool, false);
   DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels",     GrallocFenceWithReadPixels, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.port",                   LayerScopePort, int32_t, 23456);
   DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled",             PerfWarnings, bool, false);
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -307,16 +307,20 @@ gfxWindowsPlatform::gfxWindowsPlatform()
 #ifdef CAIRO_HAS_D2D_SURFACE
     RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter());
     mD2DDevice = nullptr;
 #endif
     RegisterStrongMemoryReporter(new GfxD2DVramReporter());
 
     UpdateRenderMode();
 
+    if (gfxPrefs::Direct2DUse1_1()) {
+      InitD3D11Devices();
+    }
+
     RegisterStrongMemoryReporter(new GPUAdapterReporter());
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
     mDeviceManager = nullptr;
 
     // not calling FT_Done_FreeType because cairo may still hold references to
@@ -433,17 +437,22 @@ gfxWindowsPlatform::UpdateRenderMode()
 #endif
 
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
     BackendType defaultBackend = BackendType::CAIRO;
     if (mRenderMode == RENDER_DIRECT2D) {
       canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
       contentMask |= BackendTypeBit(BackendType::DIRECT2D);
-      defaultBackend = BackendType::DIRECT2D;
+      if (gfxPrefs::Direct2DUse1_1() && Factory::SupportsD2D1()) {
+        contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
+        defaultBackend = BackendType::DIRECT2D1_1;
+      } else {
+        defaultBackend = BackendType::DIRECT2D;
+      }
     } else {
       canvasMask |= BackendTypeBit(BackendType::SKIA);
     }
     contentMask |= BackendTypeBit(BackendType::SKIA);
     InitBackendPrefs(canvasMask, defaultBackend,
                      contentMask, defaultBackend);
 }
 
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -179,16 +179,18 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wi
     if CONFIG['MOZ_ENABLE_DWRITE_FONT']:
         # gfxDWriteFontList.cpp forces NSPR logging, so it cannot be built in unified mode.
         SOURCES += [
             'gfxD2DSurface.cpp',
             'gfxDWriteCommon.cpp',
             'gfxDWriteFontList.cpp',
             'gfxDWriteFonts.cpp',
         ]
+    if CONFIG['MOZ_ENABLE_DIRECT2D1_1']:
+        DEFINES['USE_D2D1_1'] = True
 
 # Are we targeting x86 or x64?  If so, build gfxAlphaRecoverySSE2.cpp.
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += ['gfxAlphaRecoverySSE2.cpp']
     # The file uses SSE2 intrinsics, so it needs special compile flags on some
     # compilers.
     SOURCES['gfxAlphaRecoverySSE2.cpp'].flags += CONFIG['SSE2_FLAGS']