diff --git a/gfx/vr/VRManager.cpp b/gfx/vr/VRManager.cpp index ef74553aaa79..fd518f3d2009 100644 --- a/gfx/vr/VRManager.cpp +++ b/gfx/vr/VRManager.cpp @@ -261,6 +261,13 @@ void VRManager::UpdateRequestedDevices() { * at the VR display's native refresh rate. **/ void VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp) { +#if defined(XP_WIN) && defined(NIGHTLY_BUILD) + // For Firefox Reality PC telemetry only. + if (PR_GetEnv("MOZ_FXR")) { + ProcessTelemetryEvent(); + } +#endif + if (mState != VRManagerState::Active) { return; } @@ -420,6 +427,37 @@ void VRManager::Run100msTasks() { CheckForShutdown(); } +void VRManager::ProcessTelemetryEvent() { + mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/); + MOZ_ASSERT(!shmem.HasExternalShmem()); + if (shmem.JoinShMem()) { + mozilla::gfx::VRTelemetryState telemetryState = {0}; + shmem.PullTelemetryState(telemetryState); + + if (telemetryState.uid != 0) { + if (telemetryState.installedFrom) { + MOZ_ASSERT(telemetryState.installedFromValue <= 0x07, + "VRTelemetryId::INSTALLED_FROM only allows 3 bits."); + Telemetry::Accumulate(Telemetry::FXRPC_FF_INSTALLATION_FROM, + telemetryState.installedFromValue); + } + if (telemetryState.entryMethod) { + MOZ_ASSERT(telemetryState.entryMethodValue <= 0x07, + "VRTelemetryId::ENTRY_METHOD only allows 3 bits."); + Telemetry::Accumulate(Telemetry::FXRPC_ENTRY_METHOD, + telemetryState.entryMethodValue); + } + if (telemetryState.firstRun) { + Telemetry::ScalarSet(Telemetry::ScalarID::FXRPC_ISFIRSTRUN, + telemetryState.firstRunValue); + } + + telemetryState = {0}; + shmem.PushTelemetryState(telemetryState); + } + } +} + void VRManager::CheckForInactiveTimeout() { // Shut down the VR devices when not in use if (mVRDisplaysRequested || mVRDisplaysRequestedNonFocus || diff --git a/gfx/vr/VRManager.h b/gfx/vr/VRManager.h index 534a37207ce2..74f5ff32ca61 100644 --- a/gfx/vr/VRManager.h +++ b/gfx/vr/VRManager.h @@ -83,6 +83,7 @@ class VRManager : nsIObserver { uint32_t GetOptimalTaskInterval(); void PullState(const std::function& aWaitCondition = nullptr); void PushState(const bool aNotifyCond = false); + void ProcessTelemetryEvent(); static uint32_t AllocateDisplayID(); void DispatchVRDisplayInfoUpdate(); diff --git a/gfx/vr/VRShMem.cpp b/gfx/vr/VRShMem.cpp index 77e60fa8744f..778a27e54cf0 100644 --- a/gfx/vr/VRShMem.cpp +++ b/gfx/vr/VRShMem.cpp @@ -629,6 +629,7 @@ void VRShMem::PushWindowState(VRWindowState& aState) { } #endif // defined(XP_WIN) } + void VRShMem::PullWindowState(VRWindowState& aState) { #if defined(XP_WIN) if (!mExternalShmem) { @@ -645,6 +646,37 @@ void VRShMem::PullWindowState(VRWindowState& aState) { #endif // defined(XP_WIN) } +void VRShMem::PushTelemetryState(VRTelemetryState& aState) { +#if defined(XP_WIN) + if (!mExternalShmem) { + return; + } + + bool status = true; + WaitForMutex lock(mMutex); + status = lock.GetStatus(); + if (status) { + memcpy((void*)&(mExternalShmem->telemetryState), (void*)&aState, + sizeof(VRTelemetryState)); + } +#endif // defined(XP_WIN) +} +void VRShMem::PullTelemetryState(VRTelemetryState& aState) { +#if defined(XP_WIN) + if (!mExternalShmem) { + return; + } + + bool status = true; + WaitForMutex lock(mMutex); + status = lock.GetStatus(); + if (status) { + memcpy((void*)&aState, (void*)&(mExternalShmem->telemetryState), + sizeof(VRTelemetryState)); + } +#endif // defined(XP_WIN) +} + void VRShMem::SendEvent(uint64_t aWindowID, mozilla::gfx::VRFxEventType aEventType, mozilla::gfx::VRFxEventState aEventState) { diff --git a/gfx/vr/VRShMem.h b/gfx/vr/VRShMem.h index f7dbc559f7bc..1dfa2c958244 100644 --- a/gfx/vr/VRShMem.h +++ b/gfx/vr/VRShMem.h @@ -46,6 +46,9 @@ class VRShMem final { void PushWindowState(VRWindowState& aState); void PullWindowState(VRWindowState& aState); + void PushTelemetryState(VRTelemetryState& aState); + void PullTelemetryState(VRTelemetryState& aState); + void SendIMEState(uint64_t aWindowID, mozilla::gfx::VRFxEventState aImeState); void SendFullscreenState(uint64_t aWindowID, bool aFullscreen); void SendShutdowmState(uint64_t aWindowID); diff --git a/gfx/vr/external_api/moz_external_vr.h b/gfx/vr/external_api/moz_external_vr.h index 6f9b4230098a..e2b48dbaa3cb 100644 --- a/gfx/vr/external_api/moz_external_vr.h +++ b/gfx/vr/external_api/moz_external_vr.h @@ -47,8 +47,8 @@ namespace gfx { // and mapped files if we have both release and nightlies // running at the same time? Or...what if we have multiple // release builds running on same machine? (Bug 1563232) -#define SHMEM_VERSION "0.0.6" -static const int32_t kVRExternalVersion = 13; +#define SHMEM_VERSION "0.0.7" +static const int32_t kVRExternalVersion = 14; // We assign VR presentations to groups with a bitmask. // Currently, we will only display either content or chrome. @@ -543,6 +543,41 @@ struct VRWindowState { char signalName[32]; }; +enum class VRTelemetryId : uint8_t { + NONE = 0, + INSTALLED_FROM = 1, + ENTRY_METHOD = 2, + FIRST_RUN = 3, + TOTAL = 4, +}; + +enum class VRTelemetryInstallFrom: uint8_t { + User = 0, + FxR = 1, + HTC = 2, + Valve = 3, + TOTAL = 4, +}; + +enum class VRTelemetryEntryMethod: uint8_t { + SystemBtn = 0, + Library = 1, + Gaze = 2, + TOTAL = 3, +}; + +struct VRTelemetryState { + uint32_t uid; + + bool installedFrom : 1; + bool entryMethod : 1; + bool firstRun : 1; + + uint8_t installedFromValue : 3; + uint8_t entryMethodValue : 3; + bool firstRunValue : 1; +}; + struct VRExternalShmem { int32_t version; int32_t size; @@ -570,6 +605,7 @@ struct VRExternalShmem { #endif // !defined(__ANDROID__) #if defined(XP_WIN) VRWindowState windowState; + VRTelemetryState telemetryState; #endif #ifdef MOZILLA_INTERNAL_API void Clear() volatile { diff --git a/gfx/vr/vrhost/vrhost.def b/gfx/vr/vrhost/vrhost.def index 1aad1b674ffd..7a80c3b247a3 100644 --- a/gfx/vr/vrhost/vrhost.def +++ b/gfx/vr/vrhost/vrhost.def @@ -12,3 +12,4 @@ EXPORTS CloseVRWindow PRIVATE SendUIMessageToVRWindow PRIVATE WaitForVREvent PRIVATE + SendVRTelemetry PRIVATE \ No newline at end of file diff --git a/gfx/vr/vrhost/vrhostapi.cpp b/gfx/vr/vrhost/vrhostapi.cpp index 50d2c4d10fea..508e379a5fcd 100644 --- a/gfx/vr/vrhost/vrhostapi.cpp +++ b/gfx/vr/vrhost/vrhostapi.cpp @@ -13,9 +13,21 @@ #include #include #include +#include #include "windows.h" +class VRShmemInstance { + public: + VRShmemInstance() = delete; + VRShmemInstance(const VRShmemInstance& aRHS) = delete; + + static mozilla::gfx::VRShMem& GetInstance() { + static mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/); + return shmem; + } +}; + // VRWindowManager adds a level of indirection so that system HWND isn't exposed // outside of these APIs class VRWindowManager { @@ -85,6 +97,62 @@ class VRWindowManager { }; VRWindowManager* VRWindowManager::Instance = nullptr; +class VRTelemetryManager { + public: + void SendTelemetry(uint32_t aTelemetryId, uint32_t aValue) { + if (!aTelemetryId) { + return; + } + + mozilla::gfx::VRTelemetryState telemetryState = {0}; + VRShmemInstance::GetInstance().PullTelemetryState(telemetryState); + + if (telemetryState.uid == 0) { + telemetryState.uid = sUid; + } + + switch (mozilla::gfx::VRTelemetryId(aTelemetryId)) { + case mozilla::gfx::VRTelemetryId::INSTALLED_FROM: + MOZ_ASSERT(aValue <= 0x07, + "VRTelemetryId::INSTALLED_FROM only allows 3 bits."); + telemetryState.installedFrom = true; + telemetryState.installedFromValue = aValue; + break; + case mozilla::gfx::VRTelemetryId::ENTRY_METHOD: + MOZ_ASSERT(aValue <= 0x07, + "VRTelemetryId::ENTRY_METHOD only allows 3 bits."); + telemetryState.entryMethod = true; + telemetryState.entryMethodValue = aValue; + break; + case mozilla::gfx::VRTelemetryId::FIRST_RUN: + MOZ_ASSERT(aValue <= 0x01, + "VRTelemetryId::FIRST_RUN only allows 1 bit."); + telemetryState.firstRun = true; + telemetryState.firstRunValue = aValue; + break; + default: + MOZ_CRASH("Undefined VR telemetry type."); + break; + } + VRShmemInstance::GetInstance().PushTelemetryState(telemetryState); + ++sUid; + } + + static VRTelemetryManager* GetManager() { + if (Instance == nullptr) { + Instance = new VRTelemetryManager(); + } + return Instance; + } + + private: + static VRTelemetryManager* Instance; + static uint32_t sUid; // It starts from 1, Zero means the data is read yet + // from VRManager. +}; +uint32_t VRTelemetryManager::sUid = 1; +VRTelemetryManager* VRTelemetryManager::Instance = nullptr; + // Struct to send params to StartFirefoxThreadProc struct StartFirefoxParams { char* firefoxFolder; @@ -130,17 +198,6 @@ DWORD StartFirefoxThreadProc(_In_ LPVOID lpParameter) { return 0; } -class VRShmemInstance { - public: - VRShmemInstance() = delete; - VRShmemInstance(const VRShmemInstance& aRHS) = delete; - - static mozilla::gfx::VRShMem& GetInstance() { - static mozilla::gfx::VRShMem shmem(nullptr, true /*aRequiresMutex*/); - return shmem; - } -}; - // 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 @@ -305,4 +362,13 @@ void SendUIMessageToVRWindow(uint32_t nVRWindowID, uint32_t msg, break; } } +} + +void SendVRTelemetry(uint32_t nVRWindowID, uint32_t telemetryId, + uint32_t value) { + HWND hwnd = VRWindowManager::GetManager()->GetHWND(nVRWindowID); + if (hwnd == nullptr) { + return; + } + VRTelemetryManager::GetManager()->SendTelemetry(telemetryId, value); } \ No newline at end of file diff --git a/gfx/vr/vrhost/vrhostex.h b/gfx/vr/vrhost/vrhostex.h index 5d23538504b2..e2c8f451830d 100644 --- a/gfx/vr/vrhost/vrhostex.h +++ b/gfx/vr/vrhost/vrhostex.h @@ -28,3 +28,6 @@ typedef void (*PFN_SENDUIMSG)(uint32_t nVRWindowID, uint32_t msg, typedef void (*PFN_WAITFORVREVENT)(uint32_t& nVRWindowID, uint32_t& eventType, uint32_t& eventData1, uint32_t& eventData2); + +typedef void (*PFN_SENDVRTELEMETRY)(uint32_t nVRWindowID, uint32_t telemetryId, + uint32_t value); \ No newline at end of file diff --git a/gfx/vr/vrhost/vrhostnightly.def b/gfx/vr/vrhost/vrhostnightly.def index 7f30ab243178..0a849e37ce34 100644 --- a/gfx/vr/vrhost/vrhostnightly.def +++ b/gfx/vr/vrhost/vrhostnightly.def @@ -14,6 +14,7 @@ EXPORTS CloseVRWindow PRIVATE SendUIMessageToVRWindow PRIVATE WaitForVREvent PRIVATE + SendVRTelemetry PRIVATE ;+= Exports only available in Nightlies for testing SampleExport PRIVATE