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); }
void VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, PTextureParent* aTexture, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect) { if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) { // Suppress layers hidden by the group mask return; } 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; } if (!SubmitFrame(sourceD3D11, texSize, aLeftEyeRect, aRightEyeRect)) { return; } /** * Trigger the next VSync immediately after we are successfully * submitting frames. As SubmitFrame is responsible for throttling * the render loop, if we don't successfully call it, we shouldn't trigger * NotifyVRVsync immediately, as it will run unbounded. * If NotifyVRVsync is not called here due to SubmitFrame failing, the * fallback "watchdog" code in VRDisplayHost::NotifyVSync() will cause * frames to continue at a lower refresh rate until frame submission * succeeds again. */ VRManager *vm = VRManager::Get(); MOZ_ASSERT(vm); vm->NotifyVRVsync(mDisplayInfo.mDisplayID); }
void WebRenderBridgeParent::ProcessWebRenderParentCommands(InfallibleTArray<WebRenderParentCommand>& aCommands) { for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) { const WebRenderParentCommand& cmd = aCommands[i]; switch (cmd.type()) { case WebRenderParentCommand::TOpAddExternalImage: { const OpAddExternalImage& op = cmd.get_OpAddExternalImage(); Range<const wr::ImageKey> keys(&op.key(), 1); // Check if key is obsoleted. if (keys[0].mNamespace != mIdNamespace) { break; } MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get()); MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(keys[0])) == mActiveImageKeys.end()); mActiveImageKeys.insert(wr::AsUint64(keys[0])); RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId())); if (!host) { NS_ERROR("CompositableHost does not exist"); break; } if (!gfxEnv::EnableWebRenderRecording()) { TextureHost* texture = host->GetAsTextureHostForComposite(); if (!texture) { NS_ERROR("TextureHost does not exist"); break; } WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost(); if (wrTexture) { wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey()); break; } } RefPtr<DataSourceSurface> dSurf = host->GetAsSurface(); if (!dSurf) { NS_ERROR("TextureHost does not return DataSourceSurface"); break; } DataSourceSurface::MappedSurface map; if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) { NS_ERROR("DataSourceSurface failed to map"); break; } IntSize size = dSurf->GetSize(); wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat()); auto slice = Range<uint8_t>(map.mData, size.height * map.mStride); mApi->AddImage(keys[0], descriptor, slice); dSurf->Unmap(); break; } case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: { const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline(); mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(), op.scBounds(), op.scTransform(), op.scaleToSize(), op.filter(), op.mixBlendMode()); break; } case WebRenderParentCommand::TCompositableOperation: { if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) { NS_ERROR("ReceiveCompositableUpdate failed"); } break; } case WebRenderParentCommand::TOpAddCompositorAnimations: { const OpAddCompositorAnimations& op = cmd.get_OpAddCompositorAnimations(); CompositorAnimations data(Move(op.data())); if (data.animations().Length()) { mAnimStorage->SetAnimations(data.id(), data.animations()); mActiveAnimations.insert(data.id()); // Store the default opacity if (op.opacity().type() == OptionalOpacity::Tfloat) { mAnimStorage->SetAnimatedValue(data.id(), op.opacity().get_float()); } // Store the default transform if (op.transform().type() == OptionalTransform::TMatrix4x4) { Matrix4x4 transform(Move(op.transform().get_Matrix4x4())); mAnimStorage->SetAnimatedValue(data.id(), Move(transform)); } } break; } default: { // other commands are handle on the child break; } } } }