--- 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",