/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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 "VRDisplayHost.h" #include "gfxVR.h" #if defined(XP_WIN) #include <d3d11.h> #include "gfxWindowsPlatform.h" #include "../layers/d3d11/CompositorD3D11.h" #include "mozilla/layers/TextureD3D11.h" #endif using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; VRDisplayHost::VRDisplayHost(VRDeviceType aType) : mInputFrameID(0) { MOZ_COUNT_CTOR(VRDisplayHost); mDisplayInfo.mType = aType; mDisplayInfo.mDisplayID = VRDisplayManager::AllocateDisplayID(); mDisplayInfo.mIsPresenting = false; for (int i = 0; i < kMaxLatencyFrames; i++) { mLastSensorState[i].Clear(); } } VRDisplayHost::~VRDisplayHost() { MOZ_COUNT_DTOR(VRDisplayHost); } void VRDisplayHost::AddLayer(VRLayerParent *aLayer) { mLayers.AppendElement(aLayer); if (mLayers.Length() == 1) { StartPresentation(); } mDisplayInfo.mIsPresenting = mLayers.Length() > 0; // Ensure that the content process receives the change immediately VRManager* vm = VRManager::Get(); vm->RefreshVRDisplays(); } void VRDisplayHost::RemoveLayer(VRLayerParent *aLayer) { mLayers.RemoveElement(aLayer); if (mLayers.Length() == 0) { StopPresentation(); } mDisplayInfo.mIsPresenting = mLayers.Length() > 0; // Ensure that the content process receives the change immediately VRManager* vm = VRManager::Get(); vm->RefreshVRDisplays(); } #if defined(XP_WIN) void VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, const int32_t& aInputFrameID, PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { // aInputFrameID is no longer controlled by content with the WebVR 1.1 API // update; however, we will later use this code to enable asynchronous // submission of multiple layers to be composited. This will enable // us to build browser UX that remains responsive even when content does // not consistently submit frames. int32_t inputFrameID = aInputFrameID; if (inputFrameID == 0) { inputFrameID = mInputFrameID; } if (inputFrameID < 0) { // Sanity check to prevent invalid memory access on builds with assertions // disabled. inputFrameID = 0; } VRHMDSensorState sensorState = mLastSensorState[inputFrameID % kMaxLatencyFrames]; // It is possible to get a cache miss on mLastSensorState if latency is // longer than kMaxLatencyFrames. An optimization would be to find a frame // that is closer than the one selected with the modulus. // If we hit this; however, latency is already so high that the site is // un-viewable and a more accurate pose prediction is not likely to // compensate. TextureHost* th = TextureHost::AsTextureHost(aTexture); // WebVR doesn't use the compositor to compose the frame, so use // AutoLockTextureHostWithoutCompositor here. AutoLockTextureHostWithoutCompositor autoLock(th); if (autoLock.Failed()) { NS_WARNING("Failed to lock the VR layer texture"); return; } CompositableTextureSourceRef source; if (!th->BindTextureSource(source)) { NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource"); return; } MOZ_ASSERT(source); IntSize texSize = source->GetSize(); TextureSourceD3D11* sourceD3D11 = source->AsSourceD3D11(); if (!sourceD3D11) { NS_WARNING("WebVR support currently only implemented for D3D11"); return; } SubmitFrame(sourceD3D11, texSize, sensorState, aLeftEyeRect, aRightEyeRect); } #else void VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, const int32_t& aInputFrameID, PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { NS_WARNING("WebVR only supported in Windows."); } #endif bool VRDisplayHost::CheckClearDisplayInfoDirty() { if (mDisplayInfo == mLastUpdateDisplayInfo) { return false; } mLastUpdateDisplayInfo = mDisplayInfo; return true; } VRControllerHost::VRControllerHost(VRDeviceType aType) { MOZ_COUNT_CTOR(VRControllerHost); mControllerInfo.mType = aType; mControllerInfo.mControllerID = VRDisplayManager::AllocateDisplayID(); } VRControllerHost::~VRControllerHost() { MOZ_COUNT_DTOR(VRControllerHost); } const VRControllerInfo& VRControllerHost::GetControllerInfo() const { return mControllerInfo; } void VRControllerHost::SetIndex(uint32_t aIndex) { mIndex = aIndex; } uint32_t VRControllerHost::GetIndex() { return mIndex; } void VRControllerHost::SetButtonPressed(uint64_t aBit) { mButtonPressed = aBit; } uint64_t VRControllerHost::GetButtonPressed() { return mButtonPressed; } void VRControllerHost::SetPose(const dom::GamepadPoseState& aPose) { mPose = aPose; } const dom::GamepadPoseState& VRControllerHost::GetPose() { return mPose; }