Clarify hololens loop

This commit is contained in:
Paul Rouget 2019-08-01 02:00:04 +02:00
parent 196c511d5e
commit b7667ff362
3 changed files with 50 additions and 58 deletions

View file

@ -488,7 +488,8 @@ impl ServoGlue {
.host_callbacks .host_callbacks
.on_allow_navigation(url.to_string()); .on_allow_navigation(url.to_string());
let window_event = WindowEvent::AllowNavigationResponse(pipeline_id, data); let window_event = WindowEvent::AllowNavigationResponse(pipeline_id, data);
let _ = self.process_event(window_event); self.events.push(window_event);
let _ = self.perform_updates();
} }
}, },
EmbedderMsg::HistoryChanged(entries, current) => { EmbedderMsg::HistoryChanged(entries, current) => {

View file

@ -22,6 +22,8 @@ namespace winrt::ServoApp::implementation {
BrowserPage::BrowserPage() { BrowserPage::BrowserPage() {
log("BrowserPage::BrowserPage()"); log("BrowserPage::BrowserPage()");
InitializeComponent(); InitializeComponent();
InitializeConditionVariable(&mGLCondVar);
InitializeCriticalSection(&mGLLock);
Loaded(std::bind(&BrowserPage::OnPageLoaded, this, _1, _2)); Loaded(std::bind(&BrowserPage::OnPageLoaded, this, _1, _2));
Window::Current().CoreWindow().VisibilityChanged( Window::Current().CoreWindow().VisibilityChanged(
std::bind(&BrowserPage::OnVisibilityChanged, this, _1, _2)); std::bind(&BrowserPage::OnVisibilityChanged, this, _1, _2));
@ -31,15 +33,13 @@ void BrowserPage::Shutdown() {
log("BrowserPage::Shutdown()"); log("BrowserPage::Shutdown()");
if (mServo != nullptr) { if (mServo != nullptr) {
if (!IsLoopRunning()) { if (!mLooping) {
// FIXME: this should not happen. In that case, we can't send the // FIXME: this should not happen. In that case, we can't send the
// shutdown event to Servo. // shutdown event to Servo.
} else { } else {
HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sShutdownEvent);
RunOnGLThread([=] { mServo->RequestShutdown(); }); RunOnGLThread([=] { mServo->RequestShutdown(); });
log("Waiting for Servo to shutdown"); mLoopTask->wait();
::WaitForSingleObject(hEvent, INFINITE); mLoopTask.reset();
StopRenderLoop();
mServo.reset(); mServo.reset();
} }
} }
@ -63,10 +63,10 @@ void BrowserPage::OnVisibilityChanged(CoreWindow const &,
// stopping the event loop, which we can't recover from yet (see comment in // stopping the event loop, which we can't recover from yet (see comment in
// Loop()) // Loop())
// if (visible && !IsLoopRunning()) { // if (visible && !mLooping) {
// StartRenderLoop(); // StartRenderLoop();
//} //}
// if (!visible && IsLoopRunning()) { // if (!visible && mLooping) {
// StopRenderLoop(); // StopRenderLoop();
//} //}
} }
@ -92,15 +92,9 @@ void BrowserPage::RecoverFromLostDevice() {
/**** GL THREAD LOOP ****/ /**** GL THREAD LOOP ****/
bool BrowserPage::IsLoopRunning() { void BrowserPage::Loop() {
return mLoopTask != nullptr && !mLoopTask->is_done();
}
void BrowserPage::Loop(cancellation_token cancel) {
log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId()); log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId());
HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sWakeupEvent);
mOpenGLES.MakeCurrent(mRenderSurface); mOpenGLES.MakeCurrent(mRenderSurface);
EGLint panelWidth = 0; EGLint panelWidth = 0;
@ -118,51 +112,48 @@ void BrowserPage::Loop(cancellation_token cancel) {
throw winrt::hresult_error(E_FAIL, L"Recovering loop unimplemented"); throw winrt::hresult_error(E_FAIL, L"Recovering loop unimplemented");
} }
// mServo->SetBatchMode(true); mServo->SetBatchMode(true);
// FIXME: ^ this should be necessary as we call perform_update
// ourself. But enabling batch mode will make clicking a link
// not working because during the click, this thread is not
// waiting on the hEvent object. See the "wakeup" comment.
log("Entering loop"); while (true) {
while (!cancel.is_canceled()) { EnterCriticalSection(&mGLLock);
// Block until wakeup is called. while (mTasks.size() == 0 && !mAnimating && mLooping) {
// Or run full speed if animating (see OnAnimatingChanged), SleepConditionVariableCS(&mGLCondVar, &mGLLock, INFINITE);
// it will endup blocking on Flush to limit rendering to 60FPS }
if (!mAnimating) { if (!mLooping) {
::WaitForSingleObject(hEvent, INFINITE); LeaveCriticalSection(&mGLLock);
break;
} }
mTasksMutex.lock();
for (auto &&task : mTasks) { for (auto &&task : mTasks) {
task(); task();
} }
mTasks.clear(); mTasks.clear();
mTasksMutex.unlock(); LeaveCriticalSection(&mGLLock);
mServo->PerformUpdates(); mServo->PerformUpdates();
} }
log("Leaving loop");
mServo->DeInit(); mServo->DeInit();
cancel_current_task(); cancel_current_task();
} // namespace winrt::ServoApp::implementation } // namespace winrt::ServoApp::implementation
void BrowserPage::StartRenderLoop() { void BrowserPage::StartRenderLoop() {
if (IsLoopRunning()) { if (mLooping) {
#if defined _DEBUG #if defined _DEBUG
throw winrt::hresult_error(E_FAIL, L"GL thread is already looping"); throw winrt::hresult_error(E_FAIL, L"GL thread is already looping");
#else #else
return; return;
#endif #endif
} }
mLooping = true;
log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId()); log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId());
auto token = mLoopCancel.get_token(); auto task = Concurrency::create_task([=] { Loop(); });
mLoopTask = std::make_unique<Concurrency::task<void>>( mLoopTask = std::make_unique<Concurrency::task<void>>(task);
Concurrency::create_task([=] { Loop(token); }, token));
} }
void BrowserPage::StopRenderLoop() { void BrowserPage::StopRenderLoop() {
if (IsLoopRunning()) { if (mLooping) {
mLoopCancel.cancel(); EnterCriticalSection(&mGLLock);
WakeUp(); mLooping = false;
LeaveCriticalSection(&mGLLock);
WakeConditionVariable(&mGLCondVar);
mLoopTask->wait(); mLoopTask->wait();
mLoopTask.reset(); mLoopTask.reset();
} }
@ -192,9 +183,9 @@ void BrowserPage::OnHistoryChanged(bool back, bool forward) {
} }
void BrowserPage::OnShutdownComplete() { void BrowserPage::OnShutdownComplete() {
log("Servo notified ShutdownComplete"); EnterCriticalSection(&mGLLock);
HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sShutdownEvent); mLooping = false;
::SetEvent(hEvent); LeaveCriticalSection(&mGLLock);
} }
void BrowserPage::OnAlert(std::wstring message) { void BrowserPage::OnAlert(std::wstring message) {
@ -225,15 +216,17 @@ void BrowserPage::Flush() {
void BrowserPage::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); } void BrowserPage::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); }
void BrowserPage::WakeUp() { void BrowserPage::WakeUp() {
// FIXME: this won't work if it's triggered while the thread is not RunOnGLThread([=] { });
// waiting. We need a better looping logic.
HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sWakeupEvent);
::SetEvent(hEvent);
} }
bool BrowserPage::OnAllowNavigation(std::wstring) { return true; } bool BrowserPage::OnAllowNavigation(std::wstring) { return true; }
void BrowserPage::OnAnimatingChanged(bool animating) { mAnimating = animating; } void BrowserPage::OnAnimatingChanged(bool animating) {
EnterCriticalSection(&mGLLock);
mAnimating = animating;
LeaveCriticalSection(&mGLLock);
WakeConditionVariable(&mGLCondVar);
}
template <typename Callable> void BrowserPage::RunOnUIThread(Callable cb) { template <typename Callable> void BrowserPage::RunOnUIThread(Callable cb) {
swapChainPanel().Dispatcher().RunAsync( swapChainPanel().Dispatcher().RunAsync(
@ -300,10 +293,10 @@ void BrowserPage::OnSurfaceClicked(IInspectable const &,
} }
void BrowserPage::RunOnGLThread(std::function<void()> task) { void BrowserPage::RunOnGLThread(std::function<void()> task) {
mTasksMutex.lock(); EnterCriticalSection(&mGLLock);
mTasks.push_back(task); mTasks.push_back(task);
mTasksMutex.unlock(); LeaveCriticalSection(&mGLLock);
WakeUp(); WakeConditionVariable(&mGLCondVar);
} }
} // namespace winrt::ServoApp::implementation } // namespace winrt::ServoApp::implementation

View file

@ -11,9 +11,6 @@
namespace winrt::ServoApp::implementation { namespace winrt::ServoApp::implementation {
static char sWakeupEvent[] = "SIGNAL_WAKEUP";
static char sShutdownEvent[] = "SIGNAL_SHUTDOWN";
struct BrowserPage : BrowserPageT<BrowserPage>, struct BrowserPage : BrowserPageT<BrowserPage>,
public servo::ServoDelegate { public servo::ServoDelegate {
public: public:
@ -66,21 +63,22 @@ private:
void StartRenderLoop(); void StartRenderLoop();
void StopRenderLoop(); void StopRenderLoop();
void Loop(Concurrency::cancellation_token); void Loop();
bool IsLoopRunning();
Concurrency::cancellation_token_source mLoopCancel;
std::unique_ptr<Concurrency::task<void>> mLoopTask; std::unique_ptr<Concurrency::task<void>> mLoopTask;
winrt::ServoApp::ImmersiveViewSource mImmersiveViewSource; winrt::ServoApp::ImmersiveViewSource mImmersiveViewSource;
EGLSurface mRenderSurface{EGL_NO_SURFACE}; EGLSurface mRenderSurface{EGL_NO_SURFACE};
std::unique_ptr<servo::Servo> mServo; std::unique_ptr<servo::Servo> mServo;
std::vector<std::function<void()>> mTasks; std::vector<std::function<void()>> mTasks;
std::mutex mTasksMutex;
CRITICAL_SECTION mGLLock;
CONDITION_VARIABLE mGLCondVar;
bool mAnimating = false;
bool mLooping = false;
OpenGLES mOpenGLES; // FIXME: shared pointer OpenGLES mOpenGLES; // FIXME: shared pointer
bool mAnimating;
}; };
} // namespace winrt::ServoApp::implementation } // namespace winrt::ServoApp::implementation