Bug 1335971: Allow uploading on the client side on Intel hardware. r=mattwoodrow
authorBas Schouten <bschouten@mozilla.com>
Thu, 02 Feb 2017 13:24:57 +0000
changeset 469890 b240c8d4075bdd3e019a125ec9dcedc050b9644f
parent 469889 ed54c5d4314a7dee126093fa520bdd5ae517b660
child 469891 bdc513580a45e6392816a8de4f3da0c8da5e72b0
push id43881
push userbmo:gps@mozilla.com
push dateThu, 02 Feb 2017 23:49:03 +0000
reviewersmattwoodrow
bugs1335971
milestone54.0a1
Bug 1335971: Allow uploading on the client side on Intel hardware. r=mattwoodrow MozReview-Commit-ID: GeVYccWK7xY
gfx/layers/IMFYCbCrImage.cpp
gfx/thebes/DeviceManagerDx.cpp
gfx/thebes/gfxPrefs.h
--- a/gfx/layers/IMFYCbCrImage.cpp
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -241,16 +241,28 @@ IMFYCbCrImage::GetTextureClient(KnowsCom
   LayersBackend backend = aForwarder->GetCompositorBackendType();
   if (!device || backend != LayersBackend::LAYERS_D3D11) {
     if (backend == LayersBackend::LAYERS_D3D9 ||
         backend == LayersBackend::LAYERS_D3D11) {
       return GetD3D9TextureClient(aForwarder);
     }
     return nullptr;
   }
+ 
+  HRESULT hr;
+  RefPtr<ID3D10Multithread> mt;
+  hr = device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
+
+  if (FAILED(hr)) {
+    return nullptr;
+  }
+
+  if (!mt->GetMultithreadProtected()) {
+    return nullptr;
+  }
 
   if (!gfx::DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
     return nullptr;
   }
 
   if (mData.mYStride < 0 || mData.mCbCrStride < 0) {
     // D3D11 only supports unsigned stride values.
     return nullptr;
@@ -261,39 +273,61 @@ IMFYCbCrImage::GetTextureClient(KnowsCom
 
   if (device == gfx::DeviceManagerDx::Get()->GetCompositorDevice()) {
     newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
   } else {
     newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
   }
 
   RefPtr<ID3D11Texture2D> textureY;
-  D3D11_SUBRESOURCE_DATA yData = { mData.mYChannel, (UINT)mData.mYStride, 0 };
-  HRESULT hr = device->CreateTexture2D(&newDesc, &yData, getter_AddRefs(textureY));
+  hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   newDesc.Width = mData.mCbCrSize.width;
   newDesc.Height = mData.mCbCrSize.height;
 
   RefPtr<ID3D11Texture2D> textureCb;
-  D3D11_SUBRESOURCE_DATA cbData = { mData.mCbChannel, (UINT)mData.mCbCrStride, 0 };
-  hr = device->CreateTexture2D(&newDesc, &cbData, getter_AddRefs(textureCb));
+  hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCb));
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
+
   RefPtr<ID3D11Texture2D> textureCr;
-  D3D11_SUBRESOURCE_DATA crData = { mData.mCrChannel, (UINT)mData.mCbCrStride, 0 };
-  hr = device->CreateTexture2D(&newDesc, &crData, getter_AddRefs(textureCr));
+  hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureCr));
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
-  // Even though the textures we created are meant to be protected by a keyed mutex,
-  // it appears that D3D doesn't include the initial memory upload within this
-  // synchronization. Add an empty lock/unlock pair since that appears to
-  // be sufficient to make sure we synchronize.
+  // The documentation here seems to suggest using the immediate mode context
+  // on more than one thread is not allowed:
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476891(v=vs.85).aspx
+  // The Debug Layer seems to imply it is though. When the ID3D10Multithread
+  // layer is on. The Enter/Leave of the critical section shouldn't even be
+  // required but were added for extra security.
+
   {
+    AutoLockTexture lockY(textureY);
     AutoLockTexture lockCr(textureCr);
+    AutoLockTexture lockCb(textureCb);
+
+    mt->Enter();
+
+    RefPtr<ID3D11DeviceContext> ctx;
+    device->GetImmediateContext((ID3D11DeviceContext**)getter_AddRefs(ctx));
+
+    D3D11_BOX box;
+    box.front = box.top = box.left = 0;
+    box.back = 1;
+    box.right = mData.mYSize.width;
+    box.bottom = mData.mYSize.height;
+    ctx->UpdateSubresource(textureY, 0, &box, mData.mYChannel, mData.mYStride, 0);
+
+    box.right = mData.mCbCrSize.width;
+    box.bottom = mData.mCbCrSize.height;
+    ctx->UpdateSubresource(textureCb, 0, &box, mData.mCbChannel, mData.mCbCrStride, 0);
+    ctx->UpdateSubresource(textureCr, 0, &box, mData.mCrChannel, mData.mCbCrStride, 0);
+
+    mt->Leave();
   }
 
   mTextureClient = TextureClient::CreateWithData(
     DXGIYCbCrTextureData::Create(TextureFlags::DEFAULT,
                                  textureY, textureCb, textureCr,
                                  GetSize(), mData.mYSize, mData.mCbCrSize),
     TextureFlags::DEFAULT,
     aForwarder->GetTextureForwarder()
--- a/gfx/thebes/DeviceManagerDx.cpp
+++ b/gfx/thebes/DeviceManagerDx.cpp
@@ -787,17 +787,17 @@ bool
 DeviceManagerDx::CanInitializeKeyedMutexTextures()
 {
   MutexAutoLock lock(mDeviceLock);
   if (!mDeviceStatus) {
     return false;
   }
   // Disable this on all Intel devices because of crashes.
   // See bug 1292923.
-  return mDeviceStatus->adapter().VendorId != 0x8086;
+  return (mDeviceStatus->adapter().VendorId != 0x8086 || gfxPrefs::Direct3D11AllowIntelMutex());
 }
 
 bool
 DeviceManagerDx::CheckRemotePresentSupport()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -376,16 +376,17 @@ private:
   DECL_GFX_PREF(Live, "gfx.color_management.rendering_intent", CMSRenderingIntent, int32_t, 0);
 
   DECL_GFX_PREF(Once, "gfx.device-reset.limit",                DeviceResetLimitCount, int32_t, 10);
   DECL_GFX_PREF(Once, "gfx.device-reset.threshold-ms",         DeviceResetThresholdMilliseconds, int32_t, -1);
 
   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.direct3d11.reuse-decoder-device",   Direct3D11ReuseDecoderDevice, int32_t, -1);
+  DECL_GFX_PREF(Live, "gfx.direct3d11.allow-intel-mutex",      Direct3D11AllowIntelMutex, bool, true);
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
   DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll",      HidePluginsForScroll, bool, true);
   DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.port",                   LayerScopePort, int32_t, 23456);
   // Note that        "gfx.logging.level" is defined in Logging.h.
   DECL_GFX_PREF(Live, "gfx.logging.level",                     GfxLoggingLevel, int32_t, mozilla::gfx::LOG_DEFAULT);
   DECL_GFX_PREF(Once, "gfx.logging.crash.length",              GfxLoggingCrashLength, uint32_t, 16);
   DECL_GFX_PREF(Live, "gfx.logging.painted-pixel-count.enabled",GfxLoggingPaintedPixelCountEnabled, bool, false);