Bug 1555188 - Enable PuppetVRSession to work when VR process is enabled r=thomasmo

Differential Revision: https://phabricator.services.mozilla.com/D72059
This commit is contained in:
Kearwood Gilbert 2020-06-08 23:57:27 +00:00
Родитель de3c9ae058
Коммит f1e15241c4
13 изменённых файлов: 256 добавлений и 66 удалений

Просмотреть файл

@ -362,6 +362,7 @@ NS_IMPL_RELEASE_INHERITED(VRMockController, DOMEventTargetHelper)
VRMockController::VRMockController(VRServiceTest* aVRServiceTest,
uint32_t aControllerIdx)
: DOMEventTargetHelper(aVRServiceTest->GetOwner()),
mVRServiceTest(aVRServiceTest),
mControllerIdx(aControllerIdx) {
MOZ_ASSERT(aControllerIdx < kVRControllerMaxCount);
}

Просмотреть файл

@ -534,13 +534,19 @@ void VRManager::CheckForPuppetCompletion() {
}
// Notify content process about completion of puppet test scripts
if (mManagerParentRunningPuppet) {
if (mServiceHost->PuppetHasEnded()) {
Unused << mManagerParentRunningPuppet
->SendNotifyPuppetCommandBufferCompleted(true);
mManagerParentRunningPuppet = nullptr;
}
mServiceHost->CheckForPuppetCompletion();
}
}
void VRManager::NotifyPuppetComplete() {
// Notify content process about completion of puppet test scripts
if (mManagerParentRunningPuppet) {
Unused << mManagerParentRunningPuppet
->SendNotifyPuppetCommandBufferCompleted(true);
mManagerParentRunningPuppet = nullptr;
}
}
#endif // !defined(MOZ_WIDGET_ANDROID)
void VRManager::StartFrame() {

Просмотреть файл

@ -65,6 +65,7 @@ class VRManager : nsIObserver {
bool RunPuppet(const nsTArray<uint64_t>& aBuffer,
VRManagerParent* aManagerParent);
void ResetPuppet(VRManagerParent* aManagerParent);
void NotifyPuppetComplete();
#endif
void AddLayer(VRLayerParent* aLayer);
void RemoveLayer(VRLayerParent* aLayer);

Просмотреть файл

@ -12,6 +12,7 @@ namespace mozilla::gfx {
static StaticRefPtr<VRPuppetCommandBuffer> sVRPuppetCommandBufferSingleton;
/* static */
VRPuppetCommandBuffer& VRPuppetCommandBuffer::Get() {
if (sVRPuppetCommandBufferSingleton == nullptr) {
sVRPuppetCommandBufferSingleton = new VRPuppetCommandBuffer();
@ -20,6 +21,11 @@ VRPuppetCommandBuffer& VRPuppetCommandBuffer::Get() {
return *sVRPuppetCommandBufferSingleton;
}
/* static */
bool VRPuppetCommandBuffer::IsCreated() {
return sVRPuppetCommandBufferSingleton != nullptr;
}
VRPuppetCommandBuffer::VRPuppetCommandBuffer()
: mMutex("VRPuppetCommandBuffer::mMutex") {
MOZ_COUNT_CTOR(VRPuppetCommandBuffer);
@ -188,8 +194,7 @@ bool VRPuppetCommandBuffer::RunCommand(uint64_t aCommand, double aDeltaTime) {
(uint8_t*)&mPendingState + (aCommand & 0x00000000ffffffff);
break;
case VRPuppet_Command::VRPuppet_UpdateControllers:
mDataOffset = (uint8_t*)&mPendingState
.controllerState[aCommand & 0x00000000000000ff] -
mDataOffset = (uint8_t*)&mPendingState.controllerState -
(uint8_t*)&mPendingState + (aCommand & 0x00000000ffffffff);
break;
case VRPuppet_Command::VRPuppet_Commit:

Просмотреть файл

@ -178,6 +178,7 @@ class VRPuppetCommandBuffer {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::gfx::VRPuppetCommandBuffer)
static VRPuppetCommandBuffer& Get();
static bool IsCreated();
// Interface to VRTestSystem
void Submit(const nsTArray<uint64_t>& aBuffer);

Просмотреть файл

@ -34,15 +34,12 @@ VRServiceHost* VRServiceHost::Get() {
}
VRServiceHost::VRServiceHost(bool aEnableVRProcess)
: mPuppetActive(false)
#if !defined(MOZ_WIDGET_ANDROID)
,
mVRService(nullptr),
: mVRService(nullptr),
mVRProcessEnabled(aEnableVRProcess),
mVRProcessStarted(false),
mVRServiceReadyInVRProcess(false),
mVRServiceRequested(false)
#endif
{
MOZ_COUNT_CTOR(VRServiceHost);
}
@ -88,8 +85,6 @@ void VRServiceHost::Refresh() {
}
}
#if !defined(MOZ_WIDGET_ANDROID)
void VRServiceHost::CreateService(volatile VRExternalShmem* aShmem) {
MOZ_ASSERT(!mVRProcessEnabled);
mVRService = VRService::Create(aShmem);
@ -99,13 +94,7 @@ bool VRServiceHost::NeedVRProcess() {
if (!mVRProcessEnabled) {
return false;
}
if (mVRServiceRequested) {
return true;
}
if (mPuppetActive) {
return true;
}
return false;
return mVRServiceRequested;
}
void VRServiceHost::RefreshVRProcess() {
@ -146,6 +135,36 @@ void VRServiceHost::CreateVRProcess() {
Unused << gpu->SendCreateVRProcess();
}
void VRServiceHost::NotifyVRProcessStarted() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mVRProcessEnabled);
if (!mVRProcessStarted) {
// We have received this after the VR process
// has been stopped; the VR service is no
// longer running in the VR process.
return;
}
if (!VRGPUChild::IsCreated()) {
return;
}
VRGPUChild* vrGPUChild = VRGPUChild::Get();
// The VR service has started in the VR process
// If there were pending puppet commands, we
// can send them now.
// This must occur before the VRService
// is started so the buffer can be seen
// by VRPuppetSession::Initialize().
if (!mPuppetPendingCommands.IsEmpty()) {
vrGPUChild->SendPuppetSubmit(mPuppetPendingCommands);
mPuppetPendingCommands.Clear();
}
vrGPUChild->SendStartVRService();
mVRServiceReadyInVRProcess = true;
}
void VRServiceHost::ShutdownVRProcess() {
// This is only allowed to run in the main thread of the GPU process
if (!XRE_IsGPUProcess()) {
@ -176,55 +195,129 @@ void VRServiceHost::ShutdownVRProcess() {
MOZ_ASSERT(gpu);
Unused << gpu->SendShutdownVRProcess();
mVRProcessStarted = false;
mVRServiceReadyInVRProcess = false;
}
#endif // !defined(MOZ_WIDGET_ANDROID)
void VRServiceHost::PuppetSubmit(const nsTArray<uint64_t>& aBuffer) {
mPuppetActive = true;
if (mVRProcessEnabled) {
// TODO - Implement VR puppet support for VR process (Bug 1555188)
MOZ_ASSERT(false); // Not implemented
} else {
if (!mVRProcessEnabled) {
// Puppet is running in this process, submit commands directly
VRPuppetCommandBuffer::Get().Submit(aBuffer);
return;
}
// We need to send the buffer to the VR process
SendPuppetSubmitToVRProcess(aBuffer);
}
void VRServiceHost::SendPuppetSubmitToVRProcess(
const nsTArray<uint64_t>& aBuffer) {
// This is only allowed to run in the main thread of the GPU process
if (!XRE_IsGPUProcess()) {
return;
}
// Forward this to the main thread if not already there
if (!NS_IsMainThread()) {
RefPtr<Runnable> task = NS_NewRunnableFunction(
"VRServiceHost::SendPuppetSubmitToVRProcess",
[buffer{aBuffer.Clone()}]() -> void {
VRServiceHost::Get()->SendPuppetSubmitToVRProcess(buffer);
});
NS_DispatchToMainThread(task.forget());
return;
}
if (!mVRServiceReadyInVRProcess) {
// Queue the commands to be sent to the VR process once it is started
mPuppetPendingCommands.AppendElements(aBuffer);
return;
}
if (VRGPUChild::IsCreated()) {
VRGPUChild* vrGPUChild = VRGPUChild::Get();
vrGPUChild->SendPuppetSubmit(aBuffer);
}
}
void VRServiceHost::PuppetReset() {
if (mVRProcessEnabled) {
mPuppetActive = false;
if (!mVRProcessStarted) {
// Process is stopped, so puppet state is already clear
return;
}
// TODO - Implement VR puppet support for VR process (Bug 1555188)
MOZ_ASSERT(false); // Not implemented
} else if (mPuppetActive) {
if (!mVRProcessEnabled) {
// Puppet is running in this process, tell it to reset directly.
VRPuppetCommandBuffer::Get().Reset();
mPuppetActive = false;
}
mPuppetPendingCommands.Clear();
if (!mVRProcessStarted) {
// Process is stopped, so puppet state is already clear
return;
}
// We need to tell the VR process to reset the puppet
SendPuppetResetToVRProcess();
}
void VRServiceHost::SendPuppetResetToVRProcess() {
// This is only allowed to run in the main thread of the GPU process
if (!XRE_IsGPUProcess()) {
return;
}
// Forward this to the main thread if not already there
if (!NS_IsMainThread()) {
RefPtr<Runnable> task = NS_NewRunnableFunction(
"VRServiceHost::SendPuppetResetToVRProcess",
[]() -> void { VRServiceHost::Get()->SendPuppetResetToVRProcess(); });
NS_DispatchToMainThread(task.forget());
return;
}
if (VRGPUChild::IsCreated()) {
VRGPUChild* vrGPUChild = VRGPUChild::Get();
vrGPUChild->SendPuppetReset();
}
}
bool VRServiceHost::PuppetHasEnded() {
if (mVRProcessEnabled) {
if (!mVRProcessStarted) {
// The VR process will be kept alive as long
// as there is a queue in the puppet command
// buffer. If the process is stopped, we can
// infer that the queue has been cleared and
// puppet state is reset.
return true;
void VRServiceHost::CheckForPuppetCompletion() {
if (!mVRProcessEnabled) {
// Puppet is running in this process, ask it directly
if (VRPuppetCommandBuffer::Get().HasEnded()) {
VRManager::Get()->NotifyPuppetComplete();
}
// TODO - Implement VR puppet support for VR process (Bug 1555188)
MOZ_ASSERT(false); // Not implemented
return false;
}
if (!mPuppetPendingCommands.IsEmpty()) {
// There are puppet commands pending to be sent to the
// VR process once its started, thus it has not ended.
return;
}
if (!mVRProcessStarted) {
// The VR process will be kept alive as long
// as there is a queue in the puppet command
// buffer. If the process is stopped, we can
// infer that the queue has been cleared and
// puppet state is reset.
VRManager::Get()->NotifyPuppetComplete();
}
if (mPuppetActive) {
return VRPuppetCommandBuffer::Get().HasEnded();
}
// We need to ask the VR process if the puppet has ended
SendPuppetCheckForCompletionToVRProcess();
return true;
// VRGPUChild::RecvNotifyPuppetComplete will call
// VRManager::NotifyPuppetComplete if the puppet has completed
// in the VR Process.
}
void VRServiceHost::SendPuppetCheckForCompletionToVRProcess() {
// This is only allowed to run in the main thread of the GPU process
if (!XRE_IsGPUProcess()) {
return;
}
// Forward this to the main thread if not already there
if (!NS_IsMainThread()) {
RefPtr<Runnable> task = NS_NewRunnableFunction(
"VRServiceHost::SendPuppetCheckForCompletionToVRProcess", []() -> void {
VRServiceHost::Get()->SendPuppetCheckForCompletionToVRProcess();
});
NS_DispatchToMainThread(task.forget());
return;
}
if (VRGPUChild::IsCreated()) {
VRGPUChild* vrGPUChild = VRGPUChild::Get();
vrGPUChild->SendPuppetCheckForCompletion();
}
}
} // namespace gfx

Просмотреть файл

@ -19,6 +19,17 @@ namespace gfx {
struct VRExternalShmem;
class VRService;
/**
* VRServiceHost is allocated as a singleton in the GPU process.
* It is responsible for allocating VRService either within the GPU process
* or in the VR process.
* When the VR process is enabled, it maintains the state of the VR process,
* starting and stopping it as needed.
* VRServiceHost provides an interface that enables communication of the
* VRService in the same way regardless of it running within the GPU process
* or the VR process.
*/
class VRServiceHost {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::gfx::VRServiceHost)
public:
@ -29,32 +40,51 @@ class VRServiceHost {
void StartService();
void StopService();
void Shutdown();
#if !defined(MOZ_WIDGET_ANDROID)
void CreateService(volatile VRExternalShmem* aShmem);
#endif
void NotifyVRProcessStarted();
void CheckForPuppetCompletion();
void PuppetSubmit(const nsTArray<uint64_t>& aBuffer);
void PuppetReset();
bool PuppetHasEnded();
protected:
private:
explicit VRServiceHost(bool aEnableVRProcess);
~VRServiceHost();
bool mPuppetActive;
#if !defined(MOZ_WIDGET_ANDROID)
void RefreshVRProcess();
bool NeedVRProcess();
void CreateVRProcess();
void ShutdownVRProcess();
void SendPuppetResetToVRProcess();
void SendPuppetCheckForCompletionToVRProcess();
void SendPuppetSubmitToVRProcess(const nsTArray<uint64_t>& aBuffer);
// Commands pending to be sent to the puppet device
// once the VR service is started.
nsTArray<uint64_t> mPuppetPendingCommands;
RefPtr<VRService> mVRService;
// mVRProcessEnabled indicates that a separate, VR Process, should be used.
// This may be false if the VR process is disabled with the
// dom.vr.process.enabled preference or when the GPU process is disabled.
// mVRProcessEnabled will not change once the browser is started and does not
// reflect the started / stopped state of the VR Process.
bool mVRProcessEnabled;
// mVRProcessStarted is true when the VR Process is running.
bool mVRProcessStarted;
// mVRServiceReadyInVRProcess is true when the VR Process is running and the
// VRService in the VR Process is ready to accept commands.
bool mVRServiceReadyInVRProcess;
// mVRServiceRequested is true when the VRService is needed. This can be due
// to Web API activity (WebXR, WebVR), browser activity (eg, VR Video
// Playback), or a request to simulate a VR device with the VRServiceTest /
// puppet API. mVRServiceRequested indicates the intended state of the VR
// Service and is not an indication that the VR Service is ready to accept
// requests or that the VR Process is enabled or running. Toggling the
// mVRServiceRequested flag will result in the VR Service and/or the VR
// Process either starting or stopping as needed.
bool mVRServiceRequested;
#endif
};
} // namespace gfx

Просмотреть файл

@ -6,12 +6,18 @@
namespace mozilla {
namespace gfx {
// IPC for VR-Content process
// The parent process is the VR process.
// The child process is the GPU process.
async protocol PVRGPU
{
parent:
async StartVRService();
async StopVRService();
async PuppetSubmit(uint64_t[] aBuffer);
async PuppetReset();
async PuppetCheckForCompletion();
child:
async NotifyPuppetComplete();
};
} // gfx

Просмотреть файл

@ -25,13 +25,15 @@ bool VRGPUChild::InitForGPUProcess(Endpoint<PVRGPUChild>&& aEndpoint) {
}
sVRGPUChildSingleton = child;
RefPtr<Runnable> task =
NS_NewRunnableFunction("VRGPUChild::SendStartVRService", []() -> void {
VRGPUChild* vrGPUChild = VRGPUChild::Get();
vrGPUChild->SendStartVRService();
#if !defined(MOZ_WIDGET_ANDROID)
RefPtr<Runnable> task = NS_NewRunnableFunction(
"VRServiceHost::NotifyVRProcessStarted", []() -> void {
VRServiceHost* host = VRServiceHost::Get();
host->NotifyVRProcessStarted();
});
NS_DispatchToMainThread(task.forget());
#endif
return true;
}
@ -62,6 +64,15 @@ void VRGPUChild::ActorDestroy(ActorDestroyReason aWhy) {
mClosed = true;
}
mozilla::ipc::IPCResult VRGPUChild::RecvNotifyPuppetComplete() {
#if !defined(MOZ_WIDGET_ANDROID)
VRManager* vm = VRManager::Get();
mozilla::layers::CompositorThread()->Dispatch(NewRunnableMethod(
"VRManager::NotifyPuppetComplete", vm, &VRManager::NotifyPuppetComplete));
#endif
return IPC_OK();
}
bool VRGPUChild::IsClosed() { return mClosed; }
} // namespace gfx

Просмотреть файл

@ -21,6 +21,9 @@ class VRGPUChild final : public PVRGPUChild {
static bool IsCreated();
static void Shutdown();
mozilla::ipc::IPCResult RecvNotifyPuppetComplete();
mozilla::ipc::IPCResult RecvNotifyServiceStarted();
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
bool IsClosed();

Просмотреть файл

@ -78,6 +78,30 @@ mozilla::ipc::IPCResult VRGPUParent::RecvStopVRService() {
return IPC_OK();
}
mozilla::ipc::IPCResult VRGPUParent::RecvPuppetReset() {
#if !defined(MOZ_WIDGET_ANDROID)
VRPuppetCommandBuffer::Get().Reset();
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult VRGPUParent::RecvPuppetSubmit(
const nsTArray<uint64_t>& aBuffer) {
#if !defined(MOZ_WIDGET_ANDROID)
VRPuppetCommandBuffer::Get().Submit(aBuffer);
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult VRGPUParent::RecvPuppetCheckForCompletion() {
#if !defined(MOZ_WIDGET_ANDROID)
if (VRPuppetCommandBuffer::Get().HasEnded()) {
Unused << SendNotifyPuppetComplete();
}
#endif
return IPC_OK();
}
bool VRGPUParent::IsClosed() { return mClosed; }
} // namespace gfx

Просмотреть файл

@ -27,6 +27,9 @@ class VRGPUParent final : public PVRGPUParent {
void Bind(Endpoint<PVRGPUParent>&& aEndpoint);
mozilla::ipc::IPCResult RecvStartVRService();
mozilla::ipc::IPCResult RecvStopVRService();
mozilla::ipc::IPCResult RecvPuppetReset();
mozilla::ipc::IPCResult RecvPuppetSubmit(const nsTArray<uint64_t>& aBuffer);
mozilla::ipc::IPCResult RecvPuppetCheckForCompletion();
private:
explicit VRGPUParent(ProcessId aChildProcessId);

Просмотреть файл

@ -30,6 +30,12 @@ bool PuppetSession::Initialize(mozilla::gfx::VRSystemState& aSystemState,
if (!StaticPrefs::dom_vr_enabled() || !StaticPrefs::dom_vr_puppet_enabled()) {
return false;
}
if (!VRPuppetCommandBuffer::IsCreated()) {
// We only want to initialize VRPuppetCommandBuffer on the main thread.
// We can assume if it is not initialized, that the puppet display
// would not be enumerated.
return false;
}
if (aDetectRuntimesOnly) {
aSystemState.displayState.capabilityFlags |=
VRDisplayCapabilityFlags::Cap_ImmersiveVR;