mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
Add new hololens code (winrt + D3D immersive mode example)
This commit is contained in:
parent
13872eb254
commit
24d2213780
51 changed files with 4691 additions and 27 deletions
236
support/hololens/ServoApp/BrowserPage.cpp
Normal file
236
support/hololens/ServoApp/BrowserPage.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "pch.h"
|
||||
#include "logs.h"
|
||||
#include "BrowserPage.h"
|
||||
#include "BrowserPage.g.cpp"
|
||||
#include "ImmersiveView.h"
|
||||
#include "OpenGLES.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::ViewManagement;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Graphics::Holographic;
|
||||
using namespace concurrency;
|
||||
|
||||
static char sWakeupEvent[] = "SIGNAL_WAKEUP";
|
||||
|
||||
namespace winrt::ServoApp::implementation {
|
||||
BrowserPage::BrowserPage() {
|
||||
InitializeComponent();
|
||||
log("BrowserPage::BrowserPage()");
|
||||
Loaded(std::bind(&BrowserPage::OnPageLoaded, this, _1, _2));
|
||||
Window::Current().CoreWindow().VisibilityChanged(
|
||||
std::bind(&BrowserPage::OnVisibilityChanged, this, _1, _2));
|
||||
}
|
||||
|
||||
void BrowserPage::OnPageLoaded(IInspectable const &, RoutedEventArgs const &) {
|
||||
log("BrowserPage::OnPageLoaded()");
|
||||
CreateRenderSurface();
|
||||
StartRenderLoop();
|
||||
|
||||
swapChainPanel().PointerReleased(
|
||||
std::bind(&BrowserPage::OnSurfaceClicked, this, _1, _2));
|
||||
}
|
||||
|
||||
void BrowserPage::OnSurfaceClicked(IInspectable const &,
|
||||
Input::PointerRoutedEventArgs const &e) {
|
||||
auto coords = e.GetCurrentPoint(swapChainPanel());
|
||||
auto x = coords.Position().X;
|
||||
auto y = coords.Position().Y;
|
||||
|
||||
SendEventToServo({{Event::CLICK}, {x, y}});
|
||||
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
void BrowserPage::SendEventToServo(Event event) {
|
||||
mEventsMutex.lock();
|
||||
mEvents.push_back(event);
|
||||
mEventsMutex.unlock();
|
||||
Servo::sWakeUp();
|
||||
}
|
||||
|
||||
void BrowserPage::OnBackButtonClicked(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
SendEventToServo({{Event::BACK}});
|
||||
}
|
||||
|
||||
void BrowserPage::OnForwardButtonClicked(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
SendEventToServo({{Event::FORWARD}});
|
||||
}
|
||||
void BrowserPage::OnImmersiveButtonClicked(IInspectable const &,
|
||||
RoutedEventArgs const &) {
|
||||
if (HolographicSpace::IsAvailable()) {
|
||||
log("Holographic space available");
|
||||
auto v =
|
||||
winrt::Windows::ApplicationModel::Core::CoreApplication::CreateNewView(
|
||||
mImmersiveViewSource);
|
||||
auto parentId = ApplicationView::GetForCurrentView().Id();
|
||||
v.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [=]() {
|
||||
auto winId = ApplicationView::GetForCurrentView().Id();
|
||||
ApplicationViewSwitcher::SwitchAsync(winId, parentId);
|
||||
log("Immersive view started");
|
||||
});
|
||||
} else {
|
||||
log("Holographic space not available");
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPage::OnVisibilityChanged(CoreWindow const &,
|
||||
VisibilityChangedEventArgs const &args) {
|
||||
auto visible = args.Visible();
|
||||
if (visible && !IsLoopRunning()) {
|
||||
StartRenderLoop();
|
||||
}
|
||||
if (!visible && IsLoopRunning()) {
|
||||
StopRenderLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPage::CreateRenderSurface() {
|
||||
if (mRenderSurface == EGL_NO_SURFACE) {
|
||||
mRenderSurface = mOpenGLES.CreateSurface(swapChainPanel());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserPage::DestroyRenderSurface() {
|
||||
mOpenGLES.DestroySurface(mRenderSurface);
|
||||
mRenderSurface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
void BrowserPage::RecoverFromLostDevice() {
|
||||
StopRenderLoop();
|
||||
DestroyRenderSurface();
|
||||
mOpenGLES.Reset();
|
||||
CreateRenderSurface();
|
||||
StartRenderLoop();
|
||||
}
|
||||
|
||||
bool BrowserPage::IsLoopRunning() {
|
||||
return mLoopTask != nullptr && !mLoopTask->is_done();
|
||||
}
|
||||
|
||||
void BrowserPage::Loop(cancellation_token cancel) {
|
||||
log("BrowserPage::Loop(). GL thread: %i", GetCurrentThreadId());
|
||||
|
||||
HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sWakeupEvent);
|
||||
|
||||
Servo::sOnAlert = [=](std::wstring message) {
|
||||
// FIXME: make this sync
|
||||
swapChainPanel().Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::High, [=]() {
|
||||
Windows::UI::Popups::MessageDialog msg{message};
|
||||
msg.ShowAsync();
|
||||
});
|
||||
};
|
||||
|
||||
Servo::sOnTitleChanged = [=](std::wstring title) {
|
||||
swapChainPanel().Dispatcher().RunAsync(CoreDispatcherPriority::High, [=]() {
|
||||
ApplicationView::GetForCurrentView().Title(title);
|
||||
});
|
||||
};
|
||||
|
||||
Servo::sOnURLChanged = [=](std::wstring url) {
|
||||
swapChainPanel().Dispatcher().RunAsync(CoreDispatcherPriority::High,
|
||||
[=]() { urlTextbox().Text(url); });
|
||||
};
|
||||
|
||||
Servo::sMakeCurrent = [=]() {
|
||||
/* EGLint panelWidth = 0; */
|
||||
/* EGLint panelHeight = 0; */
|
||||
/* mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth,
|
||||
* &panelHeight); */
|
||||
/* glViewport(0, 0, panelWidth, panelHeight); */
|
||||
/* mServo->SetSize(panelWidth, panelHeight); */
|
||||
mOpenGLES.MakeCurrent(mRenderSurface);
|
||||
};
|
||||
|
||||
Servo::sFlush = [=]() {
|
||||
if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) {
|
||||
// The call to eglSwapBuffers might not be successful (i.e. due to Device
|
||||
// Lost) If the call fails, then we must reinitialize EGL and the GL
|
||||
// resources.
|
||||
swapChainPanel().Dispatcher().RunAsync(
|
||||
CoreDispatcherPriority::High, [this]() { RecoverFromLostDevice(); });
|
||||
}
|
||||
};
|
||||
|
||||
mOpenGLES.MakeCurrent(mRenderSurface);
|
||||
|
||||
EGLint panelWidth = 0;
|
||||
EGLint panelHeight = 0;
|
||||
mOpenGLES.GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
|
||||
glViewport(0, 0, panelWidth, panelHeight);
|
||||
mServo = std::make_unique<Servo>(panelWidth, panelHeight);
|
||||
|
||||
// mServo->SetBatchMode(true);
|
||||
// FIXME: ^ this should be necessary as 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.
|
||||
|
||||
while (!cancel.is_canceled()) {
|
||||
// Block until Servo::sWakeUp is called.
|
||||
// Or run full speed if animating (see on_animating_changed),
|
||||
// it will endup blocking on SwapBuffers to limit rendering to 60FPS
|
||||
if (!Servo::sAnimating) {
|
||||
::WaitForSingleObject(hEvent, INFINITE);
|
||||
}
|
||||
mEventsMutex.lock();
|
||||
for (auto &&e : mEvents) {
|
||||
switch (e.type) {
|
||||
case Event::CLICK: {
|
||||
auto [x, y] = e.coords;
|
||||
mServo->Click(x, y);
|
||||
break;
|
||||
}
|
||||
case Event::FORWARD:
|
||||
mServo->GoForward();
|
||||
break;
|
||||
case Event::BACK:
|
||||
mServo->GoBack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
mEvents.clear();
|
||||
mEventsMutex.unlock();
|
||||
mServo->PerformUpdates();
|
||||
}
|
||||
cancel_current_task();
|
||||
}
|
||||
|
||||
void BrowserPage::StartRenderLoop() {
|
||||
if (IsLoopRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto token = mLoopCancel.get_token();
|
||||
|
||||
Servo::sWakeUp = []() {
|
||||
// FIXME: this won't work if it's triggered while the thread is not
|
||||
// waiting. We need a better looping logic.
|
||||
HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sWakeupEvent);
|
||||
::SetEvent(hEvent);
|
||||
};
|
||||
|
||||
log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId());
|
||||
|
||||
mLoopTask = std::make_unique<Concurrency::task<void>>(
|
||||
Concurrency::create_task([=] { Loop(token); }, token));
|
||||
}
|
||||
|
||||
void BrowserPage::StopRenderLoop() {
|
||||
if (IsLoopRunning()) {
|
||||
mLoopCancel.cancel();
|
||||
mLoopTask->wait();
|
||||
mLoopTask.reset();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace winrt::ServoApp::implementation
|
Loading…
Add table
Add a link
Reference in a new issue