From 38c9490f4d535cbc5753523d3aa0949677d10513 Mon Sep 17 00:00:00 2001 From: Dale Stammen Date: Wed, 3 Jun 2015 09:19:05 -0700 Subject: [PATCH] don't delete rendering thread. SpiderMonkey needs to stay on same thread --- .../win8.1-universal/OpenGLESPage.xaml.cpp | 184 ++++++++++-------- .../win8.1-universal/OpenGLESPage.xaml.h | 17 +- .../win8.1-universal/cocos2d-js/pch.h | 12 ++ 3 files changed, 130 insertions(+), 83 deletions(-) create mode 100644 cocos/platform/win8.1-universal/cocos2d-js/pch.h diff --git a/cocos/platform/win8.1-universal/OpenGLESPage.xaml.cpp b/cocos/platform/win8.1-universal/OpenGLESPage.xaml.cpp index fc4a36bc71..ce0bc7407e 100644 --- a/cocos/platform/win8.1-universal/OpenGLESPage.xaml.cpp +++ b/cocos/platform/win8.1-universal/OpenGLESPage.xaml.cpp @@ -51,10 +51,11 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) : mRenderSurface(EGL_NO_SURFACE), mCustomRenderSurfaceSize(0,0), mUseCustomRenderSurfaceSize(false), - m_coreInput(nullptr), - m_dpi(0.0f), - m_deviceLost(false), - m_orientation(DisplayOrientations::Landscape) + mCoreInput(nullptr), + mDpi(0.0f), + mDeviceLost(false), + mVisible(false), + mOrientation(DisplayOrientations::Landscape) { InitializeComponent(); @@ -77,7 +78,7 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) : currentDisplayInformation->OrientationChanged += ref new TypedEventHandler(this, &OpenGLESPage::OnOrientationChanged); - m_orientation = currentDisplayInformation->CurrentOrientation; + mOrientation = currentDisplayInformation->CurrentOrientation; this->Loaded += ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded); @@ -111,23 +112,23 @@ OpenGLESPage::OpenGLESPage(OpenGLES* openGLES) : auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^) { // The CoreIndependentInputSource will raise pointer events for the specified device types on whichever thread it's created on. - m_coreInput = swapChainPanel->CreateCoreIndependentInputSource( + mCoreInput = swapChainPanel->CreateCoreIndependentInputSource( Windows::UI::Core::CoreInputDeviceTypes::Mouse | Windows::UI::Core::CoreInputDeviceTypes::Touch | Windows::UI::Core::CoreInputDeviceTypes::Pen ); // Register for pointer events, which will be raised on the background thread. - m_coreInput->PointerPressed += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerPressed); - m_coreInput->PointerMoved += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerMoved); - m_coreInput->PointerReleased += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerReleased); + mCoreInput->PointerPressed += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerPressed); + mCoreInput->PointerMoved += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerMoved); + mCoreInput->PointerReleased += ref new TypedEventHandler(this, &OpenGLESPage::OnPointerReleased); // Begin processing input messages as they're delivered. - m_coreInput->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit); + mCoreInput->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit); }); // Run task on a dedicated high priority background thread. - m_inputLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced); + mInputLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced); } OpenGLESPage::~OpenGLESPage() @@ -141,29 +142,30 @@ void OpenGLESPage::OnPageLoaded(Platform::Object^ sender, Windows::UI::Xaml::Rou // The SwapChainPanel has been created and arranged in the page layout, so EGL can be initialized. CreateRenderSurface(); StartRenderLoop(); + mVisible = true; } void OpenGLESPage::OnPointerPressed(Object^ sender, PointerEventArgs^ e) { - if (m_renderer) + if (mRenderer) { - m_renderer->QueuePointerEvent(PointerEventType::PointerPressed, e); + mRenderer->QueuePointerEvent(PointerEventType::PointerPressed, e); } } void OpenGLESPage::OnPointerMoved(Object^ sender, PointerEventArgs^ e) { - if (m_renderer) + if (mRenderer) { - m_renderer->QueuePointerEvent(PointerEventType::PointerMoved, e); + mRenderer->QueuePointerEvent(PointerEventType::PointerMoved, e); } } void OpenGLESPage::OnPointerReleased(Object^ sender, PointerEventArgs^ e) { - if (m_renderer) + if (mRenderer) { - m_renderer->QueuePointerEvent(PointerEventType::PointerReleased, e); + mRenderer->QueuePointerEvent(PointerEventType::PointerReleased, e); } } @@ -172,9 +174,9 @@ void OpenGLESPage::OnKeyPressed(CoreWindow^ sender, KeyEventArgs^ e) if (!e->KeyStatus.WasKeyDown) { //log("OpenGLESPage::OnKeyPressed %d", e->VirtualKey); - if (m_renderer) + if (mRenderer) { - m_renderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyPressed, e); + mRenderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyPressed, e); } } } @@ -192,9 +194,9 @@ void OpenGLESPage::OnCharacterReceived(CoreWindow^ sender, CharacterReceivedEven void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e) { //log("OpenGLESPage::OnKeyReleased %d", e->VirtualKey); - if (m_renderer) + if (mRenderer) { - m_renderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyReleased, e); + mRenderer->QueueKeyboardEvent(WinRTKeyboardEventType::KeyReleased, e); } } @@ -202,18 +204,20 @@ void OpenGLESPage::OnKeyReleased(CoreWindow^ sender, KeyEventArgs^ e) void OpenGLESPage::OnOrientationChanged(DisplayInformation^ sender, Object^ args) { critical_section::scoped_lock lock(mSwapChainPanelSizeCriticalSection); - m_orientation = sender->CurrentOrientation; + mOrientation = sender->CurrentOrientation; } void OpenGLESPage::OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args) { if (args->Visible && mRenderSurface != EGL_NO_SURFACE) { - StartRenderLoop(); + std::unique_lock locker(mSleepMutex); + mVisible = true; + mSleepCondition.notify_one(); } else { - StopRenderLoop(); + mVisible = false; } } @@ -230,15 +234,14 @@ void OpenGLESPage::OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Wi */ void OpenGLESPage::OnBackButtonPressed(Object^ sender, BackPressedEventArgs^ args) { - if (m_renderer) + if (mRenderer) { - m_renderer->QueueBackButtonEvent(); + mRenderer->QueueBackButtonEvent(); args->Handled = true; } } #endif - void OpenGLESPage::OnSwapChainPanelSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e) { // Size change events occur outside of the render thread. A lock is required when updating @@ -291,19 +294,13 @@ void OpenGLESPage::DestroyRenderSurface() void OpenGLESPage::RecoverFromLostDevice() { - // Stop the render loop, reset OpenGLES, recreate the render surface - // and start the render loop again to recover from a lost device. - - StopRenderLoop(); - - { - critical_section::scoped_lock lock(mRenderSurfaceCriticalSection); - DestroyRenderSurface(); - mOpenGLES->Reset(); - CreateRenderSurface(); - } - - StartRenderLoop(); + critical_section::scoped_lock lock(mRenderSurfaceCriticalSection); + DestroyRenderSurface(); + mOpenGLES->Reset(); + CreateRenderSurface(); + std::unique_lock locker(mSleepMutex); + mDeviceLost = false; + mSleepCondition.notify_one(); } void OpenGLESPage::TerminateApp() @@ -316,7 +313,6 @@ void OpenGLESPage::TerminateApp() mOpenGLES->DestroySurface(mRenderSurface); mOpenGLES->Cleanup(); } - } Windows::UI::Xaml::Application::Current->Exit(); } @@ -330,45 +326,60 @@ void OpenGLESPage::StartRenderLoop() } DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView(); - m_dpi = currentDisplayInformation->LogicalDpi; + mDpi = currentDisplayInformation->LogicalDpi; auto dispatcher = Windows::UI::Xaml::Window::Current->CoreWindow->Dispatcher; // Create a task for rendering that will be run on a background thread. auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([this, dispatcher](Windows::Foundation::IAsyncAction ^ action) { - critical_section::scoped_lock lock(mRenderSurfaceCriticalSection); - mOpenGLES->MakeCurrent(mRenderSurface); GLsizei panelWidth = 0; GLsizei panelHeight = 0; GetSwapChainPanelSize(&panelWidth, &panelHeight); - if (m_renderer.get() == nullptr) + if (mRenderer.get() == nullptr) { - m_renderer = std::make_shared(panelWidth, panelHeight, m_dpi, m_orientation, dispatcher, swapChainPanel); + mRenderer = std::make_shared(panelWidth, panelHeight, mDpi, mOrientation, dispatcher, swapChainPanel); } - if (m_deviceLost) - { - m_deviceLost = false; - m_renderer->DeviceLost(); - } - else - { - m_renderer->Resume(); - } + mRenderer->Resume(); - - while (action->Status == Windows::Foundation::AsyncStatus::Started && !m_deviceLost) + while (action->Status == Windows::Foundation::AsyncStatus::Started) { - GetSwapChainPanelSize(&panelWidth, &panelHeight); - m_renderer.get()->Draw(panelWidth, panelHeight, m_dpi, m_orientation); - - // run on main UI thread - if (m_renderer->AppShouldExit()) + if (!mVisible) { + mRenderer->Pause(); + } + + // wait until app is visible again or thread is cancelled + while (!mVisible) + { + std::unique_lock lock(mSleepMutex); + mSleepCondition.wait(lock); + + if (action->Status != Windows::Foundation::AsyncStatus::Started) + { + return; // thread was cancelled. Exit thread + } + + if (mVisible) + { + mRenderer->Resume(); + } + else // spurious wake up + { + continue; + } + } + + GetSwapChainPanelSize(&panelWidth, &panelHeight); + mRenderer.get()->Draw(panelWidth, panelHeight, mDpi, mOrientation); + + if (mRenderer->AppShouldExit()) + { + // run on main UI thread swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new DispatchedHandler([this]() { TerminateApp(); @@ -376,17 +387,19 @@ void OpenGLESPage::StartRenderLoop() return; } - else if (mOpenGLES->SwapBuffers(mRenderSurface) != GL_TRUE) + + EGLBoolean result = GL_FALSE; { - // The call to eglSwapBuffers might not be successful (i.e. due to Device Lost) + critical_section::scoped_lock lock(mRenderSurfaceCriticalSection); + result = mOpenGLES->SwapBuffers(mRenderSurface); + } + + if (result != GL_TRUE) + { + // The call to eglSwapBuffers was not be successful (i.e. due to Device Lost) // If the call fails, then we must reinitialize EGL and the GL resources. - - m_deviceLost = true; - - if (m_renderer) - { - m_renderer->Pause(); - } + mRenderer->Pause(); + mDeviceLost = true; // XAML objects like the SwapChainPanel must only be manipulated on the UI thread. swapChainPanel->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]() @@ -394,13 +407,28 @@ void OpenGLESPage::StartRenderLoop() RecoverFromLostDevice(); }, CallbackContext::Any)); - return; - } - } + // wait until OpenGL is reset or thread is cancelled + while (mDeviceLost) + { + std::unique_lock lock(mSleepMutex); + mSleepCondition.wait(lock); - if (m_renderer) - { - m_renderer->Pause(); + if (action->Status != Windows::Foundation::AsyncStatus::Started) + { + return; // thread was cancelled. Exit thread + } + + if (!mDeviceLost) + { + // restart cocos2d-x + mRenderer->DeviceLost(); + } + else // spurious wake up + { + continue; + } + } + } } }); @@ -413,6 +441,8 @@ void OpenGLESPage::StopRenderLoop() if (mRenderLoopWorker) { mRenderLoopWorker->Cancel(); + std::unique_lock locker(mSleepMutex); + mSleepCondition.notify_one(); mRenderLoopWorker = nullptr; } } \ No newline at end of file diff --git a/cocos/platform/win8.1-universal/OpenGLESPage.xaml.h b/cocos/platform/win8.1-universal/OpenGLESPage.xaml.h index 26e3ff1fe0..c0dbe0699a 100644 --- a/cocos/platform/win8.1-universal/OpenGLESPage.xaml.h +++ b/cocos/platform/win8.1-universal/OpenGLESPage.xaml.h @@ -21,6 +21,8 @@ #include "OpenGLES.h" #include "OpenGLESPage.g.h" #include +#include +#include #include "Cocos2dRenderer.h" @@ -51,7 +53,7 @@ namespace cocos2d void StopRenderLoop(); OpenGLES* mOpenGLES; - std::shared_ptr m_renderer; + std::shared_ptr mRenderer; Windows::Foundation::Size mSwapChainPanelSize; Concurrency::critical_section mSwapChainPanelSizeCriticalSection; @@ -64,8 +66,8 @@ namespace cocos2d Windows::Foundation::IAsyncAction^ mRenderLoopWorker; // Track user input on a background worker thread. - Windows::Foundation::IAsyncAction^ m_inputLoopWorker; - Windows::UI::Core::CoreIndependentInputSource^ m_coreInput; + Windows::Foundation::IAsyncAction^ mInputLoopWorker; + Windows::UI::Core::CoreIndependentInputSource^ mCoreInput; // Independent input handling functions. void OnPointerPressed(Platform::Object^ sender, Windows::UI::Core::PointerEventArgs^ e); @@ -77,9 +79,12 @@ namespace cocos2d void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args); - float m_dpi; - bool m_deviceLost; - Windows::Graphics::Display::DisplayOrientations m_orientation; + float mDpi; + bool mDeviceLost; + bool mVisible; + Windows::Graphics::Display::DisplayOrientations mOrientation; + std::mutex mSleepMutex; + std::condition_variable mSleepCondition; }; } diff --git a/cocos/platform/win8.1-universal/cocos2d-js/pch.h b/cocos/platform/win8.1-universal/cocos2d-js/pch.h new file mode 100644 index 0000000000..087ce3bf18 --- /dev/null +++ b/cocos/platform/win8.1-universal/cocos2d-js/pch.h @@ -0,0 +1,12 @@ +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include "mozilla\Char16.h" +#include "cocos2d.h" +#include "cocos-ext.h" + +