diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 12d0a6d6e65d..81bbaad6ced1 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -534,6 +534,15 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvPause() { return IPC_OK(); } +mozilla::ipc::IPCResult CompositorBridgeParent::RecvRequestFxrOutput() { +#ifdef XP_WIN + // Continue forwarding the request to the Widget + SwapChain + mWidget->AsWindows()->RequestFxrOutput(); +#endif + + return IPC_OK(); +} + mozilla::ipc::IPCResult CompositorBridgeParent::RecvResume() { ResumeComposition(); return IPC_OK(); diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 4b21624a7072..903a904ff06b 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -253,6 +253,7 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, FrameUniformityData* data) = 0; virtual mozilla::ipc::IPCResult RecvWillClose() = 0; virtual mozilla::ipc::IPCResult RecvPause() = 0; + virtual mozilla::ipc::IPCResult RecvRequestFxrOutput() = 0; virtual mozilla::ipc::IPCResult RecvResume() = 0; virtual mozilla::ipc::IPCResult RecvResumeAsync() = 0; virtual mozilla::ipc::IPCResult RecvNotifyChildCreated( @@ -320,6 +321,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, FrameUniformityData* aOutData) override; mozilla::ipc::IPCResult RecvWillClose() override; mozilla::ipc::IPCResult RecvPause() override; + mozilla::ipc::IPCResult RecvRequestFxrOutput() override; mozilla::ipc::IPCResult RecvResume() override; mozilla::ipc::IPCResult RecvResumeAsync() override; mozilla::ipc::IPCResult RecvNotifyChildCreated( diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.h b/gfx/layers/ipc/ContentCompositorBridgeParent.h index 0e54538832e5..5110e737fc43 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.h +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.h @@ -42,6 +42,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase { } mozilla::ipc::IPCResult RecvWillClose() override { return IPC_OK(); } mozilla::ipc::IPCResult RecvPause() override { return IPC_OK(); } + mozilla::ipc::IPCResult RecvRequestFxrOutput() override { + return IPC_FAIL_NO_REASON(this); + } mozilla::ipc::IPCResult RecvResume() override { return IPC_OK(); } mozilla::ipc::IPCResult RecvResumeAsync() override { return IPC_OK(); } mozilla::ipc::IPCResult RecvNotifyChildCreated( diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index b733f206f224..3b201aaea608 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -273,6 +273,9 @@ parent: sync EndRecording() returns (bool success); + // To set up sharing the composited output to Firefox Reality on Desktop + async RequestFxrOutput(); + child: // Send back Compositor Frame Metrics from APZCs so tiled layers can // update progressively. diff --git a/gfx/vr/moz.build b/gfx/vr/moz.build index 6d367d185c84..d2cab6c32c50 100644 --- a/gfx/vr/moz.build +++ b/gfx/vr/moz.build @@ -23,6 +23,7 @@ EXPORTS += [ 'VRDisplayPresentation.h', 'VRManager.h', 'VRPuppetCommandBuffer.h', + 'VRShMem.h', 'VRThread.h', ] diff --git a/gfx/vr/nsFxrCommandLineHandler.cpp b/gfx/vr/nsFxrCommandLineHandler.cpp index 29463d942368..aa3bb430c3ff 100644 --- a/gfx/vr/nsFxrCommandLineHandler.cpp +++ b/gfx/vr/nsFxrCommandLineHandler.cpp @@ -22,11 +22,39 @@ #include "nsCOMPtr.h" #include "windows.h" +#include "WinUtils.h" #include "VRShMem.h" NS_IMPL_ISUPPORTS(nsFxrCommandLineHandler, nsICommandLineHandler) +// nsFxrCommandLineHandler acts in the middle of bootstrapping Firefox +// Reality with desktop Firefox. Details of the processes involved are +// described below: +// +// Host +// (vrhost!CreateVRWindow) Fx Main Fx GPU +// | + + +// VRShMem creates shared + + +// memory in OS + + +// | + + +// Launch firefox.exe + + +// with --fxr + + +// | | + +// Wait for Signal... nsFxrCLH handles param + +// | joins VRShMem + +// | creates new window | +// | sets .hwndFx in VRShMem | +// | | | +// | | After compositor and +// | | swapchain created, +// | | share texture handle to +// | | VRShMem and set signal +// CreateVRWindow returns | | +// to host | | +// | | | +// + NS_IMETHODIMP nsFxrCommandLineHandler::Handle(nsICommandLine* aCmdLine) { bool handleFlagRetVal = false; @@ -60,24 +88,17 @@ nsFxrCommandLineHandler::Handle(nsICommandLine* aCmdLine) { nsPIDOMWindowOuter::From(newWindow)); HWND hwndWidget = (HWND)newWidget->GetNativeData(NS_NATIVE_WINDOW); - // The CLH should have populated this first + // The CLH should populate these members first MOZ_ASSERT(windowState.hwndFx == 0); MOZ_ASSERT(windowState.textureFx == nullptr); windowState.hwndFx = (uint64_t)hwndWidget; shmem.PushWindowState(windowState); - - // Notify the waiting process that the data is now available - HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess - FALSE, // bInheritHandle - windowState.signalName // lpName - ); - - ::SetEvent(hSignal); - shmem.LeaveShMem(); - ::CloseHandle(hSignal); + // The GPU process will notify the host that window creation is complete + // after output data is set in VRShMem + newWidget->RequestFxrOutput(); } else { MOZ_CRASH("failed to start with --fxr"); } diff --git a/gfx/vr/vrhost/vrhostapi.cpp b/gfx/vr/vrhost/vrhostapi.cpp index 6e2443a18547..f4e14b182ae7 100644 --- a/gfx/vr/vrhost/vrhostapi.cpp +++ b/gfx/vr/vrhost/vrhostapi.cpp @@ -120,6 +120,8 @@ DWORD StartFirefoxThreadProc(_In_ LPVOID lpParameter) { // This export is responsible for starting up a new VR window in Firefox and // returning data related to its creation back to the caller. +// See nsFxrCommandLineHandler::Handle for more details about the bootstrapping +// process with Firefox. void CreateVRWindow(char* firefoxFolderPath, char* firefoxProfilePath, uint32_t dxgiAdapterID, uint32_t widthHost, uint32_t heightHost, uint32_t* windowId, void** hTex, diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 6ab94cdfb9a5..a740ad23ea9e 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -2067,6 +2067,10 @@ class nsIWidget : public nsISupports { const nsTArray& aFontRangeArray, const bool aIsVertical, const LayoutDeviceIntPoint& aPoint) {} + virtual void RequestFxrOutput() { + MOZ_ASSERT(false, "This function should only execute in Windows"); + } + #if defined(MOZ_WIDGET_ANDROID) /** * RecvToolbarAnimatorMessageFromCompositor receive message from compositor diff --git a/widget/windows/WinCompositorWidget.cpp b/widget/windows/WinCompositorWidget.cpp index d8914ff9e215..41e0ceae1735 100644 --- a/widget/windows/WinCompositorWidget.cpp +++ b/widget/windows/WinCompositorWidget.cpp @@ -13,6 +13,7 @@ #include "nsWindow.h" #include "VsyncDispatcher.h" #include "WinCompositorWindowThread.h" +#include "VRShMem.h" #include @@ -337,5 +338,34 @@ void WinCompositorWidget::UpdateCompositorWndSizeIfNecessary() { mLastCompositorWndSize = size; } +// TODO: Bug 1570128 - Forward request to swapchain +// For now, this simply validates that data can be passed to Firefox Reality +// host from the GPU process +void WinCompositorWidget::RequestFxrOutput() { + mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/); + if (shmem.JoinShMem()) { + mozilla::gfx::VRWindowState windowState = {0}; + shmem.PullWindowState(windowState); + + // The CLH should have populated hwndFx first + MOZ_ASSERT(windowState.hwndFx != 0); + MOZ_ASSERT(windowState.textureFx == nullptr); + + windowState.textureFx = (HANDLE)0xFFFFFFFF; + + shmem.PushWindowState(windowState); + shmem.LeaveShMem(); + + // Notify the waiting host process that the data is now available + HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess + FALSE, // bInheritHandle + windowState.signalName // lpName + ); + + ::SetEvent(hSignal); + ::CloseHandle(hSignal); + } +} + } // namespace widget } // namespace mozilla diff --git a/widget/windows/WinCompositorWidget.h b/widget/windows/WinCompositorWidget.h index 4b45e8e29ff4..af454dac2120 100644 --- a/widget/windows/WinCompositorWidget.h +++ b/widget/windows/WinCompositorWidget.h @@ -104,6 +104,8 @@ class WinCompositorWidget : public CompositorWidget, return mTransparentSurfaceLock; } + void RequestFxrOutput(); + protected: private: HDC GetWindowSurface(); diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 8939e6ab553b..2643dfd9f737 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -657,6 +657,8 @@ nsWindow::nsWindow(bool aIsChildWindow) mSizeConstraintsScale = GetDefaultScale().scale; + mRequestFxrOutputPending = false; + sInstanceCount++; } diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index e4f27fbe5fc3..0f742442c34b 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -533,6 +533,9 @@ class nsWindow final : public nsWindowBase { already_AddRefed GetFallbackScrollSnapshot( const RECT& aRequiredClip); + void CreateCompositor() override; + void RequestFxrOutput(); + protected: nsCOMPtr mParent; nsIntSize mLastSize; @@ -692,6 +695,10 @@ class nsWindow final : public nsWindowBase { WinPointerEvents mPointerEvents; ScreenPoint mLastPanGestureFocus; + + // When true, used to indicate an async call to RequestFxrOutput to the GPU + // process after the Compositor is created + bool mRequestFxrOutputPending; }; #endif // Window_h__ diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index a154f2c1d58c..a1751cb97229 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -418,6 +418,28 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) { return result; } +// This override of CreateCompositor is to add support for sending the IPC +// call for RequesetFxrOutput as soon as the compositor for this widget is +// available. +void nsWindow::CreateCompositor() { + // there's no super?? + nsWindowBase::CreateCompositor(); + + if (mRequestFxrOutputPending) { + GetRemoteRenderer()->SendRequestFxrOutput(); + } +} + +void nsWindow::RequestFxrOutput() { + if (GetRemoteRenderer() != nullptr) { + MOZ_CRASH("RequestFxrOutput should happen before Compositor is created."); + } else { + // The compositor isn't ready, so indicate to make the IPC call when + // it is available. + mRequestFxrOutputPending = true; + } +} + LayoutDeviceIntSize nsWindowGfx::GetIconMetrics(IconSizeType aSizeType) { int32_t width = ::GetSystemMetrics(sIconMetrics[aSizeType].xMetric); int32_t height = ::GetSystemMetrics(sIconMetrics[aSizeType].yMetric);