tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

VRServiceHost.cpp (9519B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "VRServiceHost.h"
      8 #include "VRGPUChild.h"
      9 #include "VRPuppetCommandBuffer.h"
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/gfx/GPUParent.h"
     12 #include "service/VRService.h"
     13 #include "VRManager.h"
     14 
     15 namespace mozilla {
     16 namespace gfx {
     17 
     18 static StaticRefPtr<VRServiceHost> sVRServiceHostSingleton;
     19 
     20 /* static */
     21 void VRServiceHost::Init(bool aEnableVRProcess) {
     22  MOZ_ASSERT(NS_IsMainThread());
     23 
     24  if (sVRServiceHostSingleton == nullptr) {
     25    sVRServiceHostSingleton = new VRServiceHost(aEnableVRProcess);
     26    ClearOnShutdown(&sVRServiceHostSingleton);
     27  }
     28 }
     29 
     30 /* static */
     31 VRServiceHost* VRServiceHost::Get() {
     32  MOZ_ASSERT(sVRServiceHostSingleton != nullptr);
     33  return sVRServiceHostSingleton;
     34 }
     35 
     36 VRServiceHost::VRServiceHost(bool aEnableVRProcess)
     37    : mVRService(nullptr),
     38      mVRProcessEnabled(aEnableVRProcess),
     39      mVRProcessStarted(false),
     40      mVRServiceReadyInVRProcess(false),
     41      mVRServiceRequested(false)
     42 
     43 {
     44  MOZ_COUNT_CTOR(VRServiceHost);
     45 }
     46 
     47 VRServiceHost::~VRServiceHost() {
     48  MOZ_ASSERT(NS_IsMainThread());
     49  MOZ_COUNT_DTOR(VRServiceHost);
     50 }
     51 
     52 void VRServiceHost::StartService() {
     53  mVRServiceRequested = true;
     54  if (mVRProcessEnabled) {
     55    // VRService in the VR process
     56    RefreshVRProcess();
     57  } else if (mVRService) {
     58    // VRService in the GPU process if enabled, or
     59    // the parent process if the GPU process is not enabled.
     60    mVRService->Start();
     61  }
     62 }
     63 
     64 void VRServiceHost::StopService() {
     65  mVRServiceRequested = false;
     66  if (mVRProcessEnabled) {
     67    // VRService in the VR process
     68    RefreshVRProcess();
     69  } else if (mVRService) {
     70    // VRService in the GPU process if enabled, or
     71    // the parent process if the GPU process is not enabled.
     72    mVRService->Stop();
     73  }
     74 }
     75 
     76 void VRServiceHost::Shutdown() {
     77  PuppetReset();
     78  StopService();
     79  mVRService = nullptr;
     80 }
     81 
     82 void VRServiceHost::Refresh() {
     83  if (mVRService) {
     84    mVRService->Refresh();
     85  }
     86 }
     87 
     88 void VRServiceHost::CreateService(volatile VRExternalShmem* aShmem) {
     89  MOZ_ASSERT(!mVRProcessEnabled);
     90  mVRService = VRService::Create(aShmem);
     91 }
     92 
     93 bool VRServiceHost::NeedVRProcess() {
     94  if (!mVRProcessEnabled) {
     95    return false;
     96  }
     97  return mVRServiceRequested;
     98 }
     99 
    100 void VRServiceHost::RefreshVRProcess() {
    101  // Start or stop the VR process if needed
    102  if (NeedVRProcess()) {
    103    if (!mVRProcessStarted) {
    104      CreateVRProcess();
    105    }
    106  } else {
    107    if (mVRProcessStarted) {
    108      ShutdownVRProcess();
    109    }
    110  }
    111 }
    112 
    113 void VRServiceHost::CreateVRProcess() {
    114  // This is only allowed to run in the main thread of the GPU process
    115  if (!XRE_IsGPUProcess()) {
    116    return;
    117  }
    118  // Forward this to the main thread if not already there
    119  if (!NS_IsMainThread()) {
    120    RefPtr<Runnable> task = NS_NewRunnableFunction(
    121        "VRServiceHost::CreateVRProcess",
    122        []() -> void { VRServiceHost::Get()->CreateVRProcess(); });
    123    NS_DispatchToMainThread(task.forget());
    124    return;
    125  }
    126  if (mVRProcessStarted) {
    127    return;
    128  }
    129 
    130  mVRProcessStarted = true;
    131  // Using PGPU channel to tell the main process
    132  // to create the VR process.
    133  gfx::GPUParent* gpu = GPUParent::GetSingleton();
    134  MOZ_ASSERT(gpu);
    135  (void)gpu->SendCreateVRProcess();
    136 }
    137 
    138 void VRServiceHost::NotifyVRProcessStarted() {
    139  MOZ_ASSERT(NS_IsMainThread());
    140  MOZ_ASSERT(mVRProcessEnabled);
    141  if (!mVRProcessStarted) {
    142    // We have received this after the VR process
    143    // has been stopped; the VR service is no
    144    // longer running in the VR process.
    145    return;
    146  }
    147 
    148  if (!VRGPUChild::IsCreated()) {
    149    return;
    150  }
    151  VRGPUChild* vrGPUChild = VRGPUChild::Get();
    152 
    153  // The VR service has started in the VR process
    154  // If there were pending puppet commands, we
    155  // can send them now.
    156  // This must occur before the VRService
    157  // is started so the buffer can be seen
    158  // by VRPuppetSession::Initialize().
    159  if (!mPuppetPendingCommands.IsEmpty()) {
    160    vrGPUChild->SendPuppetSubmit(mPuppetPendingCommands);
    161    mPuppetPendingCommands.Clear();
    162  }
    163 
    164  vrGPUChild->SendStartVRService();
    165  mVRServiceReadyInVRProcess = true;
    166 }
    167 
    168 void VRServiceHost::ShutdownVRProcess() {
    169  // This is only allowed to run in the main thread of the GPU process
    170  if (!XRE_IsGPUProcess()) {
    171    return;
    172  }
    173  // Forward this to the main thread if not already there
    174  if (!NS_IsMainThread()) {
    175    RefPtr<Runnable> task = NS_NewRunnableFunction(
    176        "VRServiceHost::ShutdownVRProcess",
    177        []() -> void { VRServiceHost::Get()->ShutdownVRProcess(); });
    178    NS_DispatchToMainThread(task.forget());
    179    return;
    180  }
    181  if (VRGPUChild::IsCreated()) {
    182    VRGPUChild* vrGPUChild = VRGPUChild::Get();
    183    vrGPUChild->SendStopVRService();
    184    if (!vrGPUChild->IsClosed()) {
    185      vrGPUChild->Close();
    186    }
    187    VRGPUChild::Shutdown();
    188  }
    189  if (!mVRProcessStarted) {
    190    return;
    191  }
    192  // Using PGPU channel to tell the main process
    193  // to shutdown VR process.
    194  gfx::GPUParent* gpu = GPUParent::GetSingleton();
    195  MOZ_ASSERT(gpu);
    196  (void)gpu->SendShutdownVRProcess();
    197  mVRProcessStarted = false;
    198  mVRServiceReadyInVRProcess = false;
    199 }
    200 
    201 void VRServiceHost::PuppetSubmit(const nsTArray<uint64_t>& aBuffer) {
    202  if (!mVRProcessEnabled) {
    203    // Puppet is running in this process, submit commands directly
    204    VRPuppetCommandBuffer::Get().Submit(aBuffer);
    205    return;
    206  }
    207 
    208  // We need to send the buffer to the VR process
    209  SendPuppetSubmitToVRProcess(aBuffer);
    210 }
    211 
    212 void VRServiceHost::SendPuppetSubmitToVRProcess(
    213    const nsTArray<uint64_t>& aBuffer) {
    214  // This is only allowed to run in the main thread of the GPU process
    215  if (!XRE_IsGPUProcess()) {
    216    return;
    217  }
    218  // Forward this to the main thread if not already there
    219  if (!NS_IsMainThread()) {
    220    RefPtr<Runnable> task = NS_NewRunnableFunction(
    221        "VRServiceHost::SendPuppetSubmitToVRProcess",
    222        [buffer{aBuffer.Clone()}]() -> void {
    223          VRServiceHost::Get()->SendPuppetSubmitToVRProcess(buffer);
    224        });
    225    NS_DispatchToMainThread(task.forget());
    226    return;
    227  }
    228  if (!mVRServiceReadyInVRProcess) {
    229    // Queue the commands to be sent to the VR process once it is started
    230    mPuppetPendingCommands.AppendElements(aBuffer);
    231    return;
    232  }
    233  if (VRGPUChild::IsCreated()) {
    234    VRGPUChild* vrGPUChild = VRGPUChild::Get();
    235    vrGPUChild->SendPuppetSubmit(aBuffer);
    236  }
    237 }
    238 
    239 void VRServiceHost::PuppetReset() {
    240  // If we're already into ShutdownFinal, the VRPuppetCommandBuffer instance
    241  // will have been cleared, so don't try to access it after that point.
    242  if (!mVRProcessEnabled &&
    243      !(NS_IsMainThread() &&
    244        PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal))) {
    245    // Puppet is running in this process, tell it to reset directly.
    246    VRPuppetCommandBuffer::Get().Reset();
    247  }
    248 
    249  mPuppetPendingCommands.Clear();
    250  if (!mVRProcessStarted) {
    251    // Process is stopped, so puppet state is already clear
    252    return;
    253  }
    254 
    255  // We need to tell the VR process to reset the puppet
    256  SendPuppetResetToVRProcess();
    257 }
    258 
    259 void VRServiceHost::SendPuppetResetToVRProcess() {
    260  // This is only allowed to run in the main thread of the GPU process
    261  if (!XRE_IsGPUProcess()) {
    262    return;
    263  }
    264  // Forward this to the main thread if not already there
    265  if (!NS_IsMainThread()) {
    266    RefPtr<Runnable> task = NS_NewRunnableFunction(
    267        "VRServiceHost::SendPuppetResetToVRProcess",
    268        []() -> void { VRServiceHost::Get()->SendPuppetResetToVRProcess(); });
    269    NS_DispatchToMainThread(task.forget());
    270    return;
    271  }
    272  if (VRGPUChild::IsCreated()) {
    273    VRGPUChild* vrGPUChild = VRGPUChild::Get();
    274    vrGPUChild->SendPuppetReset();
    275  }
    276 }
    277 
    278 void VRServiceHost::CheckForPuppetCompletion() {
    279  if (!mVRProcessEnabled) {
    280    // Puppet is running in this process, ask it directly
    281    if (VRPuppetCommandBuffer::Get().HasEnded()) {
    282      VRManager::Get()->NotifyPuppetComplete();
    283    }
    284  }
    285  if (!mPuppetPendingCommands.IsEmpty()) {
    286    // There are puppet commands pending to be sent to the
    287    // VR process once its started, thus it has not ended.
    288    return;
    289  }
    290  if (!mVRProcessStarted) {
    291    // The VR process will be kept alive as long
    292    // as there is a queue in the puppet command
    293    // buffer.  If the process is stopped, we can
    294    // infer that the queue has been cleared and
    295    // puppet state is reset.
    296    VRManager::Get()->NotifyPuppetComplete();
    297  }
    298 
    299  // We need to ask the VR process if the puppet has ended
    300  SendPuppetCheckForCompletionToVRProcess();
    301 
    302  // VRGPUChild::RecvNotifyPuppetComplete will call
    303  // VRManager::NotifyPuppetComplete if the puppet has completed
    304  // in the VR Process.
    305 }
    306 
    307 void VRServiceHost::SendPuppetCheckForCompletionToVRProcess() {
    308  // This is only allowed to run in the main thread of the GPU process
    309  if (!XRE_IsGPUProcess()) {
    310    return;
    311  }
    312  // Forward this to the main thread if not already there
    313  if (!NS_IsMainThread()) {
    314    RefPtr<Runnable> task = NS_NewRunnableFunction(
    315        "VRServiceHost::SendPuppetCheckForCompletionToVRProcess", []() -> void {
    316          VRServiceHost::Get()->SendPuppetCheckForCompletionToVRProcess();
    317        });
    318    NS_DispatchToMainThread(task.forget());
    319    return;
    320  }
    321  if (VRGPUChild::IsCreated()) {
    322    VRGPUChild* vrGPUChild = VRGPUChild::Get();
    323    vrGPUChild->SendPuppetCheckForCompletion();
    324  }
    325 }
    326 
    327 }  // namespace gfx
    328 }  // namespace mozilla