/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 "VRDisplayPresentation.h" #include "mozilla/dom/DocGroup.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/XRWebGLLayer.h" #include "mozilla/Unused.h" #include "VRDisplayClient.h" #include "VRLayerChild.h" using namespace mozilla; using namespace mozilla::gfx; VRDisplayPresentation::VRDisplayPresentation( VRDisplayClient* aDisplayClient, const nsTArray& aLayers, uint32_t aGroup) : mDisplayClient(aDisplayClient), mDOMLayers(aLayers.Clone()), mGroup(aGroup) { CreateLayers(); } void VRDisplayPresentation::UpdateLayers( const nsTArray& aLayers) { mDOMLayers = aLayers.Clone(); CreateLayers(); } void VRDisplayPresentation::UpdateXRWebGLLayer(dom::XRWebGLLayer* aLayer) { VRManagerChild* manager = VRManagerChild::Get(); if (!manager) { // This should not happen, but let's log it and avoid a crash in case // of regression. NS_WARNING("VRManagerChild::Get returned null!"); return; } dom::HTMLCanvasElement* canvasElement = aLayer->GetCanvas(); nsCOMPtr target = canvasElement->OwnerDoc()->EventTargetFor(TaskCategory::Other); if (mLayers.Length() == 0) { // WebXR uses a single layer for now. RefPtr vrLayer = static_cast(manager->CreateVRLayer( mDisplayClient->GetDisplayInfo().GetDisplayID(), target, mGroup)); mLayers.AppendElement(vrLayer); } RefPtr vrLayer = mLayers[0]; Rect leftBounds(0.0, 0.0, 0.5, 1.0); Rect rightBounds(0.5, 0.0, 0.5, 1.0); vrLayer->Initialize(canvasElement, leftBounds, rightBounds); vrLayer->SetXRFramebuffer(aLayer->GetFramebuffer()); } uint32_t VRDisplayPresentation::GetGroup() const { return mGroup; } void VRDisplayPresentation::CreateLayers() { VRManagerChild* manager = VRManagerChild::Get(); if (!manager) { // This should not happen, but let's log it and avoid a crash in case // of regression. NS_WARNING("VRManagerChild::Get returned null!"); return; } unsigned int iLayer = 0; for (dom::VRLayer& layer : mDOMLayers) { dom::HTMLCanvasElement* canvasElement = layer.mSource; if (!canvasElement) { /// XXX In the future we will support WebVR in WebWorkers here continue; } Rect leftBounds(0.0, 0.0, 0.5, 1.0); if (layer.mLeftBounds.Length() == 4) { leftBounds.SetRect(layer.mLeftBounds[0], layer.mLeftBounds[1], layer.mLeftBounds[2], layer.mLeftBounds[3]); } else if (layer.mLeftBounds.Length() != 0) { /** * We ignore layers with an incorrect number of values. * In the future, VRDisplay.requestPresent may throw in * this case. See https://github.com/w3c/webvr/issues/71 */ continue; } Rect rightBounds(0.5, 0.0, 0.5, 1.0); if (layer.mRightBounds.Length() == 4) { rightBounds.SetRect(layer.mRightBounds[0], layer.mRightBounds[1], layer.mRightBounds[2], layer.mRightBounds[3]); } else if (layer.mRightBounds.Length() != 0) { /** * We ignore layers with an incorrect number of values. * In the future, VRDisplay.requestPresent may throw in * this case. See https://github.com/w3c/webvr/issues/71 */ continue; } nsCOMPtr target = canvasElement->OwnerDoc()->EventTargetFor(TaskCategory::Other); if (mLayers.Length() <= iLayer) { // Not enough layers, let's add one RefPtr vrLayer = static_cast(manager->CreateVRLayer( mDisplayClient->GetDisplayInfo().GetDisplayID(), target, mGroup)); if (!vrLayer) { NS_WARNING("CreateVRLayer returned null!"); continue; } vrLayer->Initialize(canvasElement, leftBounds, rightBounds); mLayers.AppendElement(vrLayer); } else { // We already have a layer, let's update it mLayers[iLayer]->Initialize(canvasElement, leftBounds, rightBounds); } iLayer++; } // Truncate any excess layers that weren't included in the updated list mLayers.SetLength(iLayer); } void VRDisplayPresentation::DestroyLayers() { for (VRLayerChild* layer : mLayers) { if (layer->IsIPCOpen()) { Unused << layer->SendDestroy(); } } mLayers.Clear(); } void VRDisplayPresentation::GetDOMLayers(nsTArray& result) { result = mDOMLayers.Clone(); } VRDisplayPresentation::~VRDisplayPresentation() { DestroyLayers(); mDisplayClient->PresentationDestroyed(); } void VRDisplayPresentation::SubmitFrame() { for (VRLayerChild* layer : mLayers) { layer->SubmitFrame(mDisplayClient->GetDisplayInfo()); break; // Currently only one layer supported, submit only the first } }