Bug 1476380 - Remove the spin wait in Android gfxVRExternal PullState calls; r?kip
MozReview-Commit-ID: 7pwMhE7emwY
--- a/gfx/vr/gfxVRExternal.cpp
+++ b/gfx/vr/gfxVRExternal.cpp
@@ -228,29 +228,40 @@ VRDisplayExternal::SubmitFrame(const lay
VRManager *vm = VRManager::Get();
VRSystemManagerExternal* manager = vm->GetExternalManager();
manager->PushState(&state, true);
sPushIndex++;
VRDisplayState displayState;
memset(&displayState, 0, sizeof(VRDisplayState));
+#if defined(MOZ_WIDGET_ANDROID)
+ manager->PullState(&displayState, &mLastSensorState, mDisplayInfo.mControllerState, [&]() {
+ return (displayState.mLastSubmittedFrameId >= aFrameId) || displayState.mSuppressFrames || !displayState.mIsConnected;
+ });
+
+ if (displayState.mSuppressFrames || !displayState.mIsConnected) {
+ // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
+ return false;
+ }
+#else
while (displayState.mLastSubmittedFrameId < aFrameId) {
if (manager->PullState(&displayState, &mLastSensorState, mDisplayInfo.mControllerState)) {
if (displayState.mSuppressFrames || !displayState.mIsConnected) {
// External implementation wants to supress frames, service has shut down or hardware has been disconnected.
return false;
}
}
#ifdef XP_WIN
Sleep(0);
#else
sleep(0);
#endif
}
+#endif // defined(MOZ_WIDGET_ANDROID)
return displayState.mLastSubmittedFrameSuccessful;
}
VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/)
: mExternalShmem(aAPIShmem)
#if !defined(MOZ_WIDGET_ANDROID)
, mSameProcess(aAPIShmem != nullptr)
@@ -258,16 +269,17 @@ VRSystemManagerExternal::VRSystemManager
{
#if defined(XP_MACOSX)
mShmemFD = 0;
#elif defined(XP_WIN)
mShmemFile = NULL;
#elif defined(MOZ_WIDGET_ANDROID)
mDoShutdown = false;
mExternalStructFailed = false;
+ mEnumerationCompleted = false;
#endif
}
VRSystemManagerExternal::~VRSystemManagerExternal()
{
CloseShmem();
}
@@ -458,23 +470,30 @@ VRSystemManagerExternal::Enumerate()
if (mDisplay == nullptr) {
OpenShmem();
if (mExternalShmem) {
VRDisplayState displayState;
memset(&displayState, 0, sizeof(VRDisplayState));
// We must block until enumeration has completed in order
// to signal that the WebVR promise should be resolved at the
// right time.
+#if defined(MOZ_WIDGET_ANDROID)
+ PullState(&displayState, nullptr, nullptr, [&](){
+ return mEnumerationCompleted;
+ });
+#else
while (!PullState(&displayState)) {
#ifdef XP_WIN
Sleep(0);
#else
sleep(0);
-#endif
+#endif // XP_WIN
}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
if (displayState.mIsConnected) {
mDisplay = new VRDisplayExternal(displayState);
}
}
}
}
bool
@@ -556,55 +575,84 @@ VRSystemManagerExternal::HandleInput()
}
void
VRSystemManagerExternal::RemoveControllers()
{
// Controller updates are handled in VRDisplayClient for VRSystemManagerExternal
}
+
+#if defined(MOZ_WIDGET_ANDROID)
+bool
+VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
+ VRHMDSensorState* aSensorState /* = nullptr */,
+ VRControllerState* aControllerState /* = nullptr */,
+ const std::function<bool()>& aWaitCondition /* = nullptr */)
+{
+ MOZ_ASSERT(mExternalShmem);
+ if (!mExternalShmem) {
+ return false;
+ }
+ bool done = false;
+ while(!done) {
+ if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
+ while (true) {
+ memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
+ if (aSensorState) {
+ memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
+ }
+ if (aControllerState) {
+ memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
+ }
+ mEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
+ mDoShutdown = aDisplayState->shutdown;
+ if (!aWaitCondition || aWaitCondition()) {
+ done = true;
+ break;
+ }
+ // Block current thead using the condition variable until data changes
+ pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond, (pthread_mutex_t*)&mExternalShmem->systemMutex);
+ }
+ pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
+ } else if (!aWaitCondition) {
+ // pthread_mutex_lock failed and we are not waiting for a condition to exit from PullState call.
+ // return false to indicate that PullState call failed
+ return false;
+ }
+ }
+ return true;
+}
+#else
bool
VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
VRHMDSensorState* aSensorState /* = nullptr */,
VRControllerState* aControllerState /* = nullptr */)
{
bool success = false;
MOZ_ASSERT(mExternalShmem);
if (mExternalShmem) {
-#if defined(MOZ_WIDGET_ANDROID)
- if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
- memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
- if (aSensorState) {
- memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
- }
- if (aControllerState) {
- memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
- }
- success = mExternalShmem->state.enumerationCompleted;
- pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
- mDoShutdown = aDisplayState->shutdown;
- }
-#else
VRExternalShmem tmp;
memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem));
if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1 && tmp.state.enumerationCompleted) {
memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState));
if (aSensorState) {
memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState));
}
if (aControllerState) {
memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
}
success = true;
}
-#endif // defined(MOZ_WIDGET_ANDROID)
}
return success;
}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
void
VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState, bool aNotifyCond)
{
MOZ_ASSERT(aBrowserState);
MOZ_ASSERT(mExternalShmem);
if (mExternalShmem) {
#if defined(MOZ_WIDGET_ANDROID)
--- a/gfx/vr/gfxVRExternal.h
+++ b/gfx/vr/gfxVRExternal.h
@@ -81,35 +81,43 @@ public:
virtual void ScanForControllers() override;
virtual void RemoveControllers() override;
virtual void VibrateHaptic(uint32_t aControllerIdx,
uint32_t aHapticIndex,
double aIntensity,
double aDuration,
const VRManagerPromise& aPromise) override;
virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
+#if defined(MOZ_WIDGET_ANDROID)
+ bool PullState(VRDisplayState* aDisplayState,
+ VRHMDSensorState* aSensorState = nullptr,
+ VRControllerState* aControllerState = nullptr,
+ const std::function<bool()>& aWaitCondition = nullptr);
+#else
bool PullState(VRDisplayState* aDisplayState,
VRHMDSensorState* aSensorState = nullptr,
VRControllerState* aControllerState = nullptr);
+#endif
void PushState(VRBrowserState* aBrowserState, const bool aNotifyCond = false);
protected:
explicit VRSystemManagerExternal(VRExternalShmem* aAPIShmem = nullptr);
virtual ~VRSystemManagerExternal();
private:
// there can only be one
RefPtr<impl::VRDisplayExternal> mDisplay;
#if defined(XP_MACOSX)
int mShmemFD;
#elif defined(XP_WIN)
HANDLE mShmemFile;
#elif defined(MOZ_WIDGET_ANDROID)
bool mDoShutdown;
bool mExternalStructFailed;
+ bool mEnumerationCompleted;
#endif
volatile VRExternalShmem* mExternalShmem;
#if !defined(MOZ_WIDGET_ANDROID)
bool mSameProcess;
#endif
void OpenShmem();