Bug 1345648 - Use ID3DDeviceContextState to support NV_dx_interop2 on D3D11 on AMD - r=kvark draft
authorJeff Gilbert <jdashg@gmail.com>
Wed, 08 Mar 2017 13:30:37 -0800
changeset 495579 6633d37aa7b6fdfb5d322e44df5cda5ad4aa008b
parent 495323 800ba54a4bd52628833c4db005ddd182586666c4
child 495580 7e44b90ef1087f1fb53d56e764f5e7446ddac67e
push id48374
push userbmo:jgilbert@mozilla.com
push dateThu, 09 Mar 2017 01:07:14 +0000
reviewerskvark
bugs1345648
milestone55.0a1
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",