Bug 1345648 - Use ID3DDeviceContextState to support NV_dx_interop2 on D3D11 on AMD - r=kvark
authorJeff Gilbert <jdashg@gmail.com>
Wed, 08 Mar 2017 13:30:37 -0800
changeset 346850 6bfe6b49c1af84a62261e50f436948a39aa01d79
parent 346849 0cd7b0a6547db7e61dda1a7406fec24f657385a7
child 346851 2c94e07a4334e883996d35b6e201a6e5519a1f8d
push id31479
push userkwierso@gmail.com
push dateFri, 10 Mar 2017 00:33:39 +0000
treeherdermozilla-central@35398cae65c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1345648
milestone55.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 1345648 - Use ID3DDeviceContextState to support NV_dx_interop2 on D3D11 on AMD - r=kvark MozReview-Commit-ID: AzUbKzQp9lT
gfx/gl/SharedSurfaceD3D11Interop.cpp
--- a/gfx/gl/SharedSurfaceD3D11Interop.cpp
+++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedSurfaceD3D11Interop.h"
 
 #include <d3d11.h>
+#include <d3d11_1.h>
 #include "gfxPrefs.h"
 #include "GLContext.h"
 #include "WGLLibrary.h"
 #include "nsPrintfCString.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 
 namespace mozilla {
 namespace gl {
@@ -109,54 +110,111 @@ while (!done) {
       <direct3d renders to the render targets and presents
        the results on the screen>
 }
 */
 
 ////////////////////////////////////////////////////////////////////////////////
 // DXInterop2Device
 
+class ScopedContextState final
+{
+    ID3D11DeviceContext1* const mD3DContext;
+    RefPtr<ID3DDeviceContextState> mOldContextState;
+
+public:
+    ScopedContextState(ID3D11DeviceContext1* d3dContext,
+                       ID3DDeviceContextState* newContextState)
+        : mD3DContext(d3dContext)
+        , mOldContextState(nullptr)
+    {
+        if (!mD3DContext)
+            return;
+
+        mD3DContext->SwapDeviceContextState(newContextState,
+                                            getter_AddRefs(mOldContextState));
+    }
+
+    ~ScopedContextState()
+    {
+        if (!mD3DContext)
+            return;
+
+        mD3DContext->SwapDeviceContextState(mOldContextState, nullptr);
+    }
+};
+
 class DXInterop2Device : public RefCounted<DXInterop2Device>
 {
 public:
     MOZ_DECLARE_REFCOUNTED_TYPENAME(DXInterop2Device)
 
     WGLLibrary* const mWGL;
     const RefPtr<ID3D11Device> mD3D; // Only needed for lifetime guarantee.
     const HANDLE mInteropDevice;
     GLContext* const mGL;
 
+    // AMD workaround.
+    const RefPtr<ID3D11DeviceContext1> mD3DContext;
+    const RefPtr<ID3DDeviceContextState> mContextState;
+
     static already_AddRefed<DXInterop2Device> Open(WGLLibrary* wgl, GLContext* gl)
     {
         MOZ_ASSERT(wgl->HasDXInterop2());
 
         const RefPtr<ID3D11Device> d3d = gfx::DeviceManagerDx::Get()->GetContentDevice();
         if (!d3d) {
             gfxCriticalNote << "DXInterop2Device::Open: Failed to create D3D11 device.";
             return nullptr;
         }
 
         if (!gl->MakeCurrent())
             return nullptr;
 
+        RefPtr<ID3D11DeviceContext1> d3dContext;
+        RefPtr<ID3DDeviceContextState> contextState;
+        if (gl->WorkAroundDriverBugs() && gl->Vendor() == GLVendor::ATI) {
+            // AMD calls ID3D10Device::Flush, so we need to be in ID3D10Device mode.
+            RefPtr<ID3D11Device1> d3d11_1;
+            auto hr = d3d->QueryInterface(__uuidof(ID3D11Device1),
+                                          getter_AddRefs(d3d11_1));
+            if (!SUCCEEDED(hr))
+                return nullptr;
+
+            d3d11_1->GetImmediateContext1(getter_AddRefs(d3dContext));
+            MOZ_ASSERT(d3dContext);
+
+            const D3D_FEATURE_LEVEL featureLevel10_0 = D3D_FEATURE_LEVEL_10_0;
+            hr = d3d11_1->CreateDeviceContextState(0, &featureLevel10_0, 1,
+                                                   D3D11_SDK_VERSION,
+                                                   __uuidof(ID3D10Device), nullptr,
+                                                   getter_AddRefs(contextState));
+            if (!SUCCEEDED(hr))
+                return nullptr;
+        }
+
         const auto interopDevice = wgl->mSymbols.fDXOpenDeviceNV(d3d);
         if (!interopDevice) {
             gfxCriticalNote << "DXInterop2Device::Open: DXOpenDevice failed.";
             return nullptr;
         }
 
-        return MakeAndAddRef<DXInterop2Device>(wgl, d3d, interopDevice, gl);
+        return MakeAndAddRef<DXInterop2Device>(wgl, d3d, interopDevice, gl, d3dContext,
+                                               contextState);
     }
 
     DXInterop2Device(WGLLibrary* wgl, ID3D11Device* d3d, HANDLE interopDevice,
-                     GLContext* gl)
+                     GLContext* gl, ID3D11DeviceContext1* d3dContext,
+                     ID3DDeviceContextState* contextState)
         : mWGL(wgl)
         , mD3D(d3d)
         , mInteropDevice(interopDevice)
         , mGL(gl)
+        , mD3DContext(d3dContext)
+        , mContextState(contextState)
     { }
 
     ~DXInterop2Device() {
         const auto isCurrent = mGL->MakeCurrent();
 
         if (mWGL->mSymbols.fDXCloseDeviceNV(mInteropDevice))
             return;
 
@@ -171,33 +229,35 @@ public:
     }
 
     HANDLE RegisterObject(void* d3dObject, GLuint name, GLenum type,
                           GLenum access) const
     {
         if (!mGL->MakeCurrent())
             return nullptr;
 
-        const auto& ret = mWGL->mSymbols.fDXRegisterObjectNV(mInteropDevice, d3dObject,
-                                                             name, type, access);
+        const ScopedContextState autoCS(mD3DContext, mContextState);
+        const auto ret = mWGL->mSymbols.fDXRegisterObjectNV(mInteropDevice, d3dObject,
+                                                            name, type, access);
         if (ret)
             return ret;
 
         const uint32_t error = GetLastError();
         const nsPrintfCString errorMessage("wglDXRegisterObject(0x%p, 0x%p, %u, 0x%04x,"
                                            " 0x%04x) failed: GetLastError(): %u\n",
                                            mInteropDevice, d3dObject, name, type, access,
                                            error);
         gfxCriticalNote << errorMessage.BeginReading();
         return nullptr;
     }
 
     bool UnregisterObject(HANDLE lockHandle) const {
         const auto isCurrent = mGL->MakeCurrent();
 
+        const ScopedContextState autoCS(mD3DContext, mContextState);
         if (mWGL->mSymbols.fDXUnregisterObjectNV(mInteropDevice, lockHandle))
             return true;
 
         if (!isCurrent) {
             // That shouldn't have failed.
             const uint32_t error = GetLastError();
             const nsPrintfCString errorMessage("wglDXUnregisterObject(0x%p, 0x%p) failed:"
                                                " GetLastError(): %u\n",