Bug 1381085 - Submit VR frames with a separate ID3DDeviceContextState
- Using a separate ID3DDeviceContextState ensures
that the WebVR context does not stomp over the
mirrored state used by the MLGPU "Advanced" Layers rendering.
MozReview-Commit-ID: 99mfdsjFrMI
--- a/dom/vr/test/reftest/reftest.list
+++ b/dom/vr/test/reftest/reftest.list
@@ -1,10 +1,11 @@
# WebVR Reftests
default-preferences pref(dom.vr.puppet.enabled,true) pref(dom.vr.test.enabled,true) pref(dom.vr.require-gesture,false) pref(dom.vr.puppet.submitframe,1)
-# VR SubmitFrame is only implemented for D3D11 and MacOSX now.
+# VR SubmitFrame is only implemented for D3D11.1 and MacOSX now.
+# Our Windows 7 test machines don't support D3D11.1, so we run these tests on Windows 8+ only.
# We need to continue to investigate why these reftests can be run well in local,
# but will be suspended until terminating on reftest D3D11 debug build.
-skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated) == draw_rect.html wrapper.html?draw_rect.png
+skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == draw_rect.html wrapper.html?draw_rect.png
# On MacOSX platform, getting different color interpolation result.
# For lower resolution Mac hardware, we need to adjust it to fuzzy-if(cocoaWidget,1,1200).
-fuzzy-if(cocoaWidget,1,600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated) == change_size.html wrapper.html?change_size.png
+fuzzy-if(cocoaWidget,1,600) skip-if((!winWidget&&release_or_beta)||Android||gtkWidget||(winWidget&&isDebugBuild)||!layersGPUAccelerated||/^Windows\x20NT\x206\.1/.test(http.oscpu)) == change_size.html wrapper.html?change_size.png
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -9,44 +9,138 @@
#include "mozilla/layers/TextureHost.h"
#include "mozilla/dom/GamepadBinding.h" // For GamepadMappingType
#if defined(XP_WIN)
#include <d3d11.h>
#include "gfxWindowsPlatform.h"
#include "../layers/d3d11/CompositorD3D11.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/layers/TextureD3D11.h"
#elif defined(XP_MACOSX)
#include "mozilla/gfx/MacIOSurface.h"
#endif
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
+VRDisplayHost::AutoRestoreRenderState::AutoRestoreRenderState(VRDisplayHost* aDisplay)
+ : mDisplay(aDisplay)
+ , mSuccess(true)
+{
+#if defined(XP_WIN)
+ ID3D11DeviceContext1* context = mDisplay->GetD3DDeviceContext();
+ ID3DDeviceContextState* state = mDisplay->GetD3DDeviceContextState();
+ if (!context || !state) {
+ mSuccess = false;
+ return;
+ }
+ context->SwapDeviceContextState(state, getter_AddRefs(mPrevDeviceContextState));
+#endif
+}
+
+VRDisplayHost::AutoRestoreRenderState::~AutoRestoreRenderState()
+{
+#if defined(XP_WIN)
+ ID3D11DeviceContext1* context = mDisplay->GetD3DDeviceContext();
+ if (context && mSuccess) {
+ context->SwapDeviceContextState(mPrevDeviceContextState, nullptr);
+ }
+#endif
+}
+
+bool
+VRDisplayHost::AutoRestoreRenderState::IsSuccess()
+{
+ return mSuccess;
+}
+
VRDisplayHost::VRDisplayHost(VRDeviceType aType)
: mFrameStarted(false)
{
MOZ_COUNT_CTOR(VRDisplayHost);
mDisplayInfo.mType = aType;
mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
mDisplayInfo.mPresentingGroups = 0;
mDisplayInfo.mGroupMask = kVRGroupContent;
mDisplayInfo.mFrameId = 0;
}
VRDisplayHost::~VRDisplayHost()
{
MOZ_COUNT_DTOR(VRDisplayHost);
}
+#if defined(XP_WIN)
+bool
+VRDisplayHost::CreateD3DObjects()
+{
+ if (!mDevice) {
+ RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
+ if (!device) {
+ NS_WARNING("VRDisplayHost::CreateD3DObjects failed to get a D3D11Device");
+ return false;
+ }
+ if (FAILED(device->QueryInterface(__uuidof(ID3D11Device1), getter_AddRefs(mDevice)))) {
+ NS_WARNING("VRDisplayHost::CreateD3DObjects failed to get a D3D11Device1");
+ return false;
+ }
+ }
+ if (!mContext) {
+ mDevice->GetImmediateContext1(getter_AddRefs(mContext));
+ if (!mContext) {
+ NS_WARNING("VRDisplayHost::CreateD3DObjects failed to get an immediate context");
+ return false;
+ }
+ }
+ if (!mDeviceContextState) {
+ D3D_FEATURE_LEVEL featureLevels[] {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0
+ };
+ mDevice->CreateDeviceContextState(0,
+ featureLevels,
+ 2,
+ D3D11_SDK_VERSION,
+ __uuidof(ID3D11Device1),
+ nullptr,
+ getter_AddRefs(mDeviceContextState));
+ }
+ if (!mDeviceContextState) {
+ NS_WARNING("VRDisplayHost::CreateD3DObjects failed to get a D3D11DeviceContextState");
+ return false;
+ }
+ return true;
+}
+
+ID3D11Device1*
+VRDisplayHost::GetD3DDevice()
+{
+ return mDevice;
+}
+
+ID3D11DeviceContext1*
+VRDisplayHost::GetD3DDeviceContext()
+{
+ return mContext;
+}
+
+ID3DDeviceContextState*
+VRDisplayHost::GetD3DDeviceContextState()
+{
+ return mDeviceContextState;
+}
+
+#endif // defined(XP_WIN)
+
void
VRDisplayHost::SetGroupMask(uint32_t aGroupMask)
{
mDisplayInfo.mGroupMask = aGroupMask;
}
bool
VRDisplayHost::GetIsConnected()
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -12,16 +12,19 @@
#include "nsCOMPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Atomics.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypedEnumBits.h"
#include "mozilla/dom/GamepadPoseState.h"
+#if defined(XP_WIN)
+#include <d3d11_1.h>
+#endif
#if defined(XP_MACOSX)
class MacIOSurface;
#endif
namespace mozilla {
namespace layers {
class PTextureParent;
#if defined(XP_WIN)
@@ -51,16 +54,29 @@ public:
uint64_t aFrameId,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect);
bool CheckClearDisplayInfoDirty();
void SetGroupMask(uint32_t aGroupMask);
bool GetIsConnected();
+ class AutoRestoreRenderState {
+ public:
+ explicit AutoRestoreRenderState(VRDisplayHost* aDisplay);
+ ~AutoRestoreRenderState();
+ bool IsSuccess();
+ private:
+ RefPtr<VRDisplayHost> mDisplay;
+#if defined(XP_WIN)
+ RefPtr<ID3DDeviceContextState> mPrevDeviceContextState;
+#endif
+ bool mSuccess;
+ };
+
protected:
explicit VRDisplayHost(VRDeviceType aType);
virtual ~VRDisplayHost();
#if defined(XP_WIN)
// Subclasses should override this SubmitFrame function.
// Returns true if the SubmitFrame call will block as necessary
// to control timing of the next frame and throttle the render loop
@@ -84,16 +100,29 @@ protected:
protected:
virtual VRHMDSensorState GetSensorState() = 0;
private:
VRDisplayInfo mLastUpdateDisplayInfo;
TimeStamp mLastFrameStart;
bool mFrameStarted;
+
+#if defined(XP_WIN)
+protected:
+ bool CreateD3DObjects();
+ RefPtr<ID3D11Device1> mDevice;
+ RefPtr<ID3D11DeviceContext1> mContext;
+ ID3D11Device1* GetD3DDevice();
+ ID3D11DeviceContext1* GetD3DDeviceContext();
+ ID3DDeviceContextState* GetD3DDeviceContextState();
+
+private:
+ RefPtr<ID3DDeviceContextState> mDeviceContextState;
+#endif
};
class VRControllerHost {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRControllerHost)
const VRControllerInfo& GetControllerInfo() const;
void SetButtonPressed(uint64_t aBit);
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -905,37 +905,24 @@ VRDisplayOculus::GetSensorState(double a
result.flags |= VRDisplayCapabilityFlags::Cap_Present;
return result;
}
void
VRDisplayOculus::StartPresentation()
{
+ if (!CreateD3DObjects()) {
+ return;
+ }
mSession->StartPresentation(IntSize(mDisplayInfo.mEyeResolution.width * 2, mDisplayInfo.mEyeResolution.height));
if (!mSession->IsRenderReady()) {
return;
}
- if (!mDevice) {
- mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
- if (!mDevice) {
- NS_WARNING("Failed to get a D3D11Device for Oculus");
- return;
- }
- }
-
- if (!mContext) {
- mDevice->GetImmediateContext(getter_AddRefs(mContext));
- if (!mContext) {
- NS_WARNING("Failed to get immediate context for Oculus");
- return;
- }
- }
-
if (!mQuadVS) {
if (FAILED(mDevice->CreateVertexShader(sLayerQuadVS.mData, sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
NS_WARNING("Failed to create vertex shader for Oculus");
return;
}
}
if (!mQuadPS) {
@@ -1043,17 +1030,26 @@ VRDisplayOculus::UpdateConstantBuffers()
}
bool
VRDisplayOculus::SubmitFrame(TextureSourceD3D11* aSource,
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect)
{
- if (!mSession->IsRenderReady() || !mDevice || !mContext) {
+ if (!CreateD3DObjects()) {
+ return false;
+ }
+
+ AutoRestoreRenderState restoreState(this);
+ if (!restoreState.IsSuccess()) {
+ return false;
+ }
+
+ if (!mSession->IsRenderReady()) {
return false;
}
/**
* XXX - We should resolve fail the promise returned by
* VRDisplay.requestPresent() when the DX11 resources fail allocation
* in VRDisplayOculus::StartPresentation().
* Bailing out here prevents the crash but content should be aware
* that frames are not being presented.
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -103,18 +103,16 @@ protected:
virtual ~VRDisplayOculus();
VRHMDSensorState GetSensorState(double absTime);
ovrHmdDesc mDesc;
RefPtr<VROculusSession> mSession;
ovrFovPort mFOVPort[2];
- RefPtr<ID3D11Device> mDevice;
- RefPtr<ID3D11DeviceContext> mContext;
ID3D11VertexShader* mQuadVS;
ID3D11PixelShader* mQuadPS;
RefPtr<ID3D11SamplerState> mLinearSamplerState;
layers::VertexShaderConstants mVSConstants;
layers::PixelShaderConstants mPSConstants;
RefPtr<ID3D11Buffer> mVSConstantBuffer;
RefPtr<ID3D11Buffer> mPSConstantBuffer;
RefPtr<ID3D11Buffer> mVertexBuffer;
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -161,27 +161,17 @@ void
VRDisplayPuppet::StartPresentation()
{
if (mIsPresenting) {
return;
}
mIsPresenting = true;
#if defined(XP_WIN)
- if (!mDevice) {
- mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
- if (!mDevice) {
- NS_WARNING("Failed to get a D3D11Device for Puppet");
- return;
- }
- }
-
- mDevice->GetImmediateContext(getter_AddRefs(mContext));
- if (!mContext) {
- NS_WARNING("Failed to get immediate context for Puppet");
+ if (!CreateD3DObjects()) {
return;
}
if (FAILED(mDevice->CreateVertexShader(sLayerQuadVS.mData,
sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
NS_WARNING("Failed to create vertex shader for Puppet");
return;
}
@@ -288,16 +278,24 @@ VRDisplayPuppet::SubmitFrame(TextureSour
const IntSize& aSize,
const gfx::Rect& aLeftEyeRect,
const gfx::Rect& aRightEyeRect)
{
if (!mIsPresenting) {
return false;
}
+ if (!CreateD3DObjects()) {
+ return false;
+ }
+ AutoRestoreRenderState restoreState(this);
+ if (!restoreState.IsSuccess()) {
+ return false;
+ }
+
VRManager *vm = VRManager::Get();
MOZ_ASSERT(vm);
switch (gfxPrefs::VRPuppetSubmitFrame()) {
case 0:
// The VR frame is not displayed.
break;
case 1:
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -51,18 +51,16 @@ protected:
void Destroy();
bool mIsPresenting;
private:
#if defined(XP_WIN)
bool UpdateConstantBuffers();
- RefPtr<ID3D11Device> mDevice;
- RefPtr<ID3D11DeviceContext> mContext;
ID3D11VertexShader* mQuadVS;
ID3D11PixelShader* mQuadPS;
RefPtr<ID3D11SamplerState> mLinearSamplerState;
layers::VertexShaderConstants mVSConstants;
layers::PixelShaderConstants mPSConstants;
RefPtr<ID3D11Buffer> mVSConstantBuffer;
RefPtr<ID3D11Buffer> mPSConstantBuffer;
RefPtr<ID3D11Buffer> mVertexBuffer;