diff --git a/.gitignore b/.gitignore
index e29d44ca3ea..de8306ff28f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,3 +44,42 @@ capture_webrender/
/unminified-js
+# Hololens artifacts
+
+support/hololens/x64/
+support/hololens/ARM/
+support/hololens/Generated\ Files
+
+# Ignore thumbnails created by Windows
+support/hololens/Thumbs.db
+
+# Ignore files built by Visual Studio
+support/hololens/*.obj
+support/hololens/*.exe
+support/hololens/*.pdb
+support/hololens/*.user
+support/hololens/*.aps
+support/hololens/*.pch
+support/hololens/*.vspscc
+support/hololens/*_i.c
+support/hololens/*_p.c
+support/hololens/*.ncb
+support/hololens/*.suo
+support/hololens/*.tlb
+support/hololens/*.tlh
+support/hololens/*.bak
+support/hololens/*.cache
+support/hololens/*.ilk
+support/hololens/*.log
+support/hololens/[Bb]in
+support/hololens/[Dd]ebug*/
+support/hololens/*.lib
+support/hololens/*.sbr
+support/hololens/obj/
+support/hololens/[Rr]elease*/
+support/hololens/_ReSharper*/
+support/hololens/[Tt]est[Rr]esult*
+support/hololens/.vs/
+
+# Nuget packages folder
+support/hololens/packages/
diff --git a/support/hololens/App.xaml b/support/hololens/App.xaml
new file mode 100644
index 00000000000..6385fb4ebc6
--- /dev/null
+++ b/support/hololens/App.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/support/hololens/App.xaml.cpp b/support/hololens/App.xaml.cpp
new file mode 100644
index 00000000000..e084de34b43
--- /dev/null
+++ b/support/hololens/App.xaml.cpp
@@ -0,0 +1,29 @@
+/* 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 "App.xaml.h"
+
+using namespace hlservo;
+
+App::App()
+{
+ InitializeComponent();
+}
+
+void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ e)
+{
+#if _DEBUG
+ if (IsDebuggerPresent()) {
+ DebugSettings->EnableFrameRateCounter = true;
+ }
+#endif
+
+ if (mPage == nullptr) {
+ mPage = ref new OpenGLESPage(&mOpenGLES);
+ }
+
+ Windows::UI::Xaml::Window::Current->Content = mPage;
+ Windows::UI::Xaml::Window::Current->Activate();
+}
diff --git a/support/hololens/App.xaml.h b/support/hololens/App.xaml.h
new file mode 100644
index 00000000000..4c109377d4c
--- /dev/null
+++ b/support/hololens/App.xaml.h
@@ -0,0 +1,21 @@
+/* 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/. */
+
+#pragma once
+
+#include "OpenGLES.h"
+#include "app.g.h"
+#include "openglespage.xaml.h"
+
+namespace hlservo {
+ref class App sealed {
+public:
+ App();
+ virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ e) override;
+
+private:
+ OpenGLESPage ^ mPage;
+ OpenGLES mOpenGLES;
+};
+}
diff --git a/support/hololens/Assets/LockScreenLogo.scale-200.png b/support/hololens/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000000..735f57adb5d
Binary files /dev/null and b/support/hololens/Assets/LockScreenLogo.scale-200.png differ
diff --git a/support/hololens/Assets/SplashScreen.scale-200.png b/support/hololens/Assets/SplashScreen.scale-200.png
new file mode 100644
index 00000000000..023e7f1feda
Binary files /dev/null and b/support/hololens/Assets/SplashScreen.scale-200.png differ
diff --git a/support/hololens/Assets/Square150x150Logo.scale-200.png b/support/hololens/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000000..af49fec1a54
Binary files /dev/null and b/support/hololens/Assets/Square150x150Logo.scale-200.png differ
diff --git a/support/hololens/Assets/Square44x44Logo.scale-200.png b/support/hololens/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000000..ce342a2ec8a
Binary files /dev/null and b/support/hololens/Assets/Square44x44Logo.scale-200.png differ
diff --git a/support/hololens/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/support/hololens/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000000..f6c02ce97e0
Binary files /dev/null and b/support/hololens/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/support/hololens/Assets/StoreLogo.png b/support/hololens/Assets/StoreLogo.png
new file mode 100644
index 00000000000..7385b56c0e4
Binary files /dev/null and b/support/hololens/Assets/StoreLogo.png differ
diff --git a/support/hololens/Assets/Wide310x150Logo.scale-200.png b/support/hololens/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000000..288995b397f
Binary files /dev/null and b/support/hololens/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/support/hololens/OpenGLES.cpp b/support/hololens/OpenGLES.cpp
new file mode 100644
index 00000000000..c217ee4fbd5
--- /dev/null
+++ b/support/hololens/OpenGLES.cpp
@@ -0,0 +1,232 @@
+/* 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 "OpenGLES.h"
+
+using namespace Platform;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+
+OpenGLES::OpenGLES()
+ : mEglConfig(nullptr)
+ , mEglDisplay(EGL_NO_DISPLAY)
+ , mEglContext(EGL_NO_CONTEXT)
+{
+ Initialize();
+}
+
+OpenGLES::~OpenGLES()
+{
+ Cleanup();
+}
+
+void OpenGLES::Initialize()
+{
+ const EGLint configAttributes[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 24,
+ EGL_STENCIL_SIZE, 8,
+ EGL_NONE
+ };
+
+ const EGLint contextAttributes[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 3,
+ EGL_NONE
+ };
+
+ // Based on Angle MS template.
+
+ const EGLint defaultDisplayAttributes[] = {
+ // These are the default display attributes, used to request ANGLE's D3D11 renderer.
+ // eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+
+ // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on
+ // mobile devices. Its syntax is subject to change, though. Please update your Visual Studio templates if you
+ // experience compilation issues with it.
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER,
+ EGL_TRUE,
+
+ // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
+ // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
+ // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification
+ // requirement.
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+
+ const EGLint fl9_3DisplayAttributes[] = {
+ // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3.
+ // These attributes are used if the call to eglInitialize fails with the default display attributes.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
+ 9,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
+ 3,
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER,
+ EGL_TRUE,
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+
+ const EGLint warpDisplayAttributes[] = {
+ // These attributes can be used to request D3D11 WARP.
+ // They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes.
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
+ EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER,
+ EGL_TRUE,
+ EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+
+ EGLConfig config = NULL;
+
+ // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay.
+ // It allows us to pass in display attributes, used to configure D3D11.
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
+ reinterpret_cast(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+ if (!eglGetPlatformDisplayEXT) {
+ throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT");
+ }
+
+ //
+ // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize,
+ // with varying parameters passed to eglGetPlatformDisplayEXT:
+ // 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+.
+ // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again
+ // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3.
+ // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
+ // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software
+ // rasterizer.
+ //
+
+ // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
+ mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
+ }
+
+ if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) {
+ // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile
+ // devices).
+ mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
+ }
+
+ if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) {
+ // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
+ mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY,
+ warpDisplayAttributes);
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
+ }
+
+ if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) {
+ // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
+ throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL");
+ }
+ }
+ }
+
+ EGLint numConfigs = 0;
+ if ((eglChooseConfig(mEglDisplay, configAttributes, &mEglConfig, 1, &numConfigs) == EGL_FALSE) ||
+ (numConfigs == 0)) {
+ throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig");
+ }
+
+ mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes);
+ if (mEglContext == EGL_NO_CONTEXT) {
+ throw Exception::CreateException(E_FAIL, L"Failed to create EGL context");
+ }
+}
+
+void OpenGLES::Cleanup()
+{
+ if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = EGL_NO_CONTEXT;
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void OpenGLES::Reset()
+{
+ Cleanup();
+ Initialize();
+}
+
+EGLSurface OpenGLES::CreateSurface(SwapChainPanel ^ panel)
+{
+ if (!panel) {
+ throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
+ }
+
+ EGLSurface surface = EGL_NO_SURFACE;
+
+ const EGLint surfaceAttributes[] = {
+ EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+ EGL_NONE
+ };
+
+ PropertySet ^ surfaceCreationProperties = ref new PropertySet();
+ surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
+
+ // How to set size and or scale:
+ // surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty),
+ // PropertyValue::CreateSize(*renderSurfaceSize));
+ // surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty),
+ // PropertyValue::CreateSingle(*resolutionScale));
+
+ surface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
+ reinterpret_cast(surfaceCreationProperties), surfaceAttributes);
+ if (surface == EGL_NO_SURFACE) {
+ throw Exception::CreateException(E_FAIL, L"Failed to create EGL surface");
+ }
+
+ return surface;
+}
+
+void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
+{
+ eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
+ eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
+}
+
+void OpenGLES::DestroySurface(const EGLSurface surface)
+{
+ if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, surface);
+ }
+}
+
+void OpenGLES::MakeCurrent(const EGLSurface surface)
+{
+ if (eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) == EGL_FALSE) {
+ throw Exception::CreateException(E_FAIL, L"Failed to make EGLSurface current");
+ }
+}
+
+EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface)
+{
+ return (eglSwapBuffers(mEglDisplay, surface));
+}
diff --git a/support/hololens/OpenGLES.h b/support/hololens/OpenGLES.h
new file mode 100644
index 00000000000..9938e7a0c9c
--- /dev/null
+++ b/support/hololens/OpenGLES.h
@@ -0,0 +1,27 @@
+/* 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/. */
+
+#pragma once
+
+class OpenGLES {
+public:
+ OpenGLES();
+ ~OpenGLES();
+
+ EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel ^ panel);
+ void GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height);
+ void DestroySurface(const EGLSurface surface);
+ void MakeCurrent(const EGLSurface surface);
+ EGLBoolean SwapBuffers(const EGLSurface surface);
+ void Reset();
+
+private:
+ void Initialize();
+ void Cleanup();
+
+private:
+ EGLDisplay mEglDisplay;
+ EGLContext mEglContext;
+ EGLConfig mEglConfig;
+};
diff --git a/support/hololens/OpenGLESPage.xaml b/support/hololens/OpenGLESPage.xaml
new file mode 100644
index 00000000000..4816b37fa08
--- /dev/null
+++ b/support/hololens/OpenGLESPage.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/support/hololens/OpenGLESPage.xaml.cpp b/support/hololens/OpenGLESPage.xaml.cpp
new file mode 100644
index 00000000000..c4c7dd21e3a
--- /dev/null
+++ b/support/hololens/OpenGLESPage.xaml.cpp
@@ -0,0 +1,154 @@
+/* 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 "OpenGLESPage.xaml.h"
+#include "Servo.h"
+
+using namespace hlservo;
+using namespace Platform;
+using namespace Concurrency;
+using namespace Windows::Foundation;
+
+static char sWakeupEvent[] = "SIGNAL_WAKEUP";
+
+OpenGLESPage::OpenGLESPage()
+ : OpenGLESPage(nullptr)
+{
+}
+
+OpenGLESPage::OpenGLESPage(OpenGLES* openGLES)
+ : mOpenGLES(openGLES)
+ , mRenderSurface(EGL_NO_SURFACE)
+{
+ InitializeComponent();
+ Windows::UI::Core::CoreWindow ^ window = Windows::UI::Xaml::Window::Current->CoreWindow;
+ window->VisibilityChanged += ref new Windows::Foundation::TypedEventHandler(this, &OpenGLESPage::OnVisibilityChanged);
+ this->Loaded += ref new Windows::UI::Xaml::RoutedEventHandler(this, &OpenGLESPage::OnPageLoaded);
+}
+
+OpenGLESPage::~OpenGLESPage()
+{
+ StopRenderLoop();
+ DestroyRenderSurface();
+}
+
+void OpenGLESPage::OnPageLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e)
+{
+ CreateRenderSurface();
+ StartRenderLoop();
+}
+
+void OpenGLESPage::OnVisibilityChanged(Windows::UI::Core::CoreWindow ^ sender,
+ Windows::UI::Core::VisibilityChangedEventArgs ^ args)
+{
+ if (args->Visible && mRenderSurface != EGL_NO_SURFACE) {
+ StartRenderLoop();
+ } else {
+ StopRenderLoop();
+ }
+}
+
+void OpenGLESPage::CreateRenderSurface()
+{
+ if (mOpenGLES && mRenderSurface == EGL_NO_SURFACE) {
+ mRenderSurface = mOpenGLES->CreateSurface(swapChainPanel);
+ }
+}
+
+void OpenGLESPage::DestroyRenderSurface()
+{
+ if (mOpenGLES) {
+ mOpenGLES->DestroySurface(mRenderSurface);
+ }
+ mRenderSurface = EGL_NO_SURFACE;
+}
+
+void OpenGLESPage::RecoverFromLostDevice()
+{
+ StopRenderLoop();
+ {
+ critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
+
+ DestroyRenderSurface();
+ mOpenGLES->Reset();
+ CreateRenderSurface();
+ }
+ StartRenderLoop();
+}
+
+void OpenGLESPage::StartRenderLoop()
+{
+ if (mRenderLoopWorker != nullptr && mRenderLoopWorker->Status == Windows::Foundation::AsyncStatus::Started) {
+ return;
+ }
+
+ auto loop = [this](Windows::Foundation::IAsyncAction ^ action) {
+ critical_section::scoped_lock lock(mRenderSurfaceCriticalSection);
+
+ HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sWakeupEvent);
+
+ // Called by Servo
+ Servo::sMakeCurrent = [this]() {
+ /* EGLint panelWidth = 0; */
+ /* EGLint panelHeight = 0; */
+ /* mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight); */
+ /* glViewport(0, 0, panelWidth, panelHeight); */
+ /* mServo->SetSize(panelWidth, panelHeight); */
+ mOpenGLES->MakeCurrent(mRenderSurface);
+ };
+
+ // Called by Servo
+ Servo::sFlush = [this]() {
+ 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(Windows::UI::Core::CoreDispatcherPriority::High,
+ ref new Windows::UI::Core::DispatchedHandler([=]() {
+ RecoverFromLostDevice();
+ }, CallbackContext::Any));
+ }
+ };
+
+ mOpenGLES->MakeCurrent(mRenderSurface);
+
+ EGLint panelWidth = 0;
+ EGLint panelHeight = 0;
+ mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight);
+ glViewport(0, 0, panelWidth, panelHeight);
+ mServo = new Servo(panelWidth, panelHeight);
+
+ while (action->Status == Windows::Foundation::AsyncStatus::Started) {
+ // 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);
+ }
+ mServo->PerformUpdates();
+ }
+ };
+
+ auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler(loop);
+
+ // Run Servo task in a high priority background thread.
+ mRenderLoopWorker = Windows::System::Threading::ThreadPool::RunAsync(
+ workItemHandler,
+ Windows::System::Threading::WorkItemPriority::High,
+ Windows::System::Threading::WorkItemOptions::TimeSliced);
+
+ Servo::sWakeUp = []() {
+ HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sWakeupEvent);
+ ::SetEvent(hEvent);
+ };
+}
+
+void OpenGLESPage::StopRenderLoop()
+{
+ if (mRenderLoopWorker) {
+ mRenderLoopWorker->Cancel();
+ mRenderLoopWorker = nullptr;
+ }
+}
diff --git a/support/hololens/OpenGLESPage.xaml.h b/support/hololens/OpenGLESPage.xaml.h
new file mode 100644
index 00000000000..ab2c8c2fd80
--- /dev/null
+++ b/support/hololens/OpenGLESPage.xaml.h
@@ -0,0 +1,37 @@
+/* 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/. */
+
+#pragma once
+
+#include "OpenGLES.h"
+#include "OpenGLESPage.g.h"
+#include "Servo.h"
+
+namespace hlservo {
+public
+ref class OpenGLESPage sealed {
+public:
+ OpenGLESPage();
+ virtual ~OpenGLESPage();
+
+ internal : OpenGLESPage(OpenGLES* openGLES);
+
+private:
+ void OnPageLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
+ void OnVisibilityChanged(Windows::UI::Core::CoreWindow ^ sender,
+ Windows::UI::Core::VisibilityChangedEventArgs ^ args);
+ void CreateRenderSurface();
+ void DestroyRenderSurface();
+ void RecoverFromLostDevice();
+ void StartRenderLoop();
+ void StopRenderLoop();
+
+ OpenGLES* mOpenGLES;
+
+ EGLSurface mRenderSurface;
+ Concurrency::critical_section mRenderSurfaceCriticalSection;
+ Windows::Foundation::IAsyncAction ^ mRenderLoopWorker;
+ Servo* mServo;
+};
+}
diff --git a/support/hololens/Package.appxmanifest b/support/hololens/Package.appxmanifest
new file mode 100644
index 00000000000..3c02095da93
--- /dev/null
+++ b/support/hololens/Package.appxmanifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+ Servo
+ Allizom
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/support/hololens/ProjectDefaultFilters.vcxproj.filters b/support/hololens/ProjectDefaultFilters.vcxproj.filters
new file mode 100644
index 00000000000..51a658ed151
--- /dev/null
+++ b/support/hololens/ProjectDefaultFilters.vcxproj.filters
@@ -0,0 +1,30 @@
+
+
+
+
+ d64db011-1240-48ad-a857-7af0ffd781dc
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+ dll;
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
diff --git a/support/hololens/Servo.cpp b/support/hololens/Servo.cpp
new file mode 100644
index 00000000000..1cbaba0fe55
--- /dev/null
+++ b/support/hololens/Servo.cpp
@@ -0,0 +1,83 @@
+/* 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 "Servo.h"
+
+extern "C" {
+#include
+}
+
+using namespace hlservo;
+
+void on_load_started() {}
+void on_load_ended() {}
+void on_title_changed(const char* title) {}
+void on_url_changed(const char* url) {}
+void on_history_changed(bool back, bool fwd) {}
+void on_shutdown_complete() {}
+
+std::function Servo::sFlush = [](){};
+std::function Servo::sMakeCurrent = [](){};
+std::function Servo::sWakeUp = [](){};
+bool Servo::sAnimating = false;
+
+void flush() {
+ Servo::sFlush();
+}
+
+void make_current() {
+ Servo::sMakeCurrent();
+}
+
+void wakeup() {
+ Servo::sWakeUp();
+}
+
+void on_animating_changed(bool aAnimating) {
+ Servo::sAnimating = aAnimating;
+}
+
+Servo::Servo(GLsizei width, GLsizei height)
+ : mAnimating(false)
+ , mWindowHeight(height)
+ , mWindowWidth(width) {
+
+ CInitOptions o;
+ o.args = NULL;
+ o.url = "http://example.com";
+ o.width = mWindowWidth;
+ o.height = mWindowHeight;
+ o.density = 1.0;
+ o.enable_subpixel_text_antialiasing = false;
+
+ CHostCallbacks c;
+ c.flush = &flush;
+ c.make_current = &make_current;
+ c.on_load_started = &on_load_started;
+ c.on_load_ended = &on_load_ended;
+ c.on_title_changed = &on_title_changed;
+ c.on_url_changed = &on_url_changed;
+ c.on_history_changed = &on_history_changed;
+ c.on_animating_changed = &on_animating_changed;
+ c.on_shutdown_complete = &on_shutdown_complete;
+
+ init_with_egl(o, &wakeup, c);
+}
+
+Servo::~Servo() {
+ deinit();
+}
+
+void Servo::PerformUpdates() {
+ perform_updates();
+}
+
+void Servo::SetSize(GLsizei width, GLsizei height) {
+ if (width != mWindowWidth || height != mWindowHeight) {
+ mWindowWidth = width;
+ mWindowHeight = height;
+ resize(mWindowWidth, mWindowHeight);
+ }
+}
diff --git a/support/hololens/Servo.h b/support/hololens/Servo.h
new file mode 100644
index 00000000000..e88eafcae0a
--- /dev/null
+++ b/support/hololens/Servo.h
@@ -0,0 +1,31 @@
+/* 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/. */
+
+#pragma once
+
+#include "pch.h"
+
+namespace hlservo {
+class Servo {
+public:
+ Servo(GLsizei width, GLsizei height);
+ ~Servo();
+ void PerformUpdates();
+ void SetSize(GLsizei width, GLsizei height);
+
+ // Static lambas called by Servo callbacks.
+
+ // Will be called from any thead
+ static std::function sWakeUp;
+ // Will be called from GL thread
+ static std::function sFlush;
+ static std::function sMakeCurrent;
+ static bool sAnimating;
+
+private:
+ GLsizei mWindowWidth;
+ GLsizei mWindowHeight;
+ bool mAnimating;
+};
+}
diff --git a/support/hololens/ServoApp.sln b/support/hololens/ServoApp.sln
new file mode 100644
index 00000000000..35fc54c426d
--- /dev/null
+++ b/support/hololens/ServoApp.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28803.352
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServoApp", "ServoApp.vcxproj", "{7134432A-49F2-4DC7-8F72-06F873A683EC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|ARM.Build.0 = Debug|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|ARM.Deploy.0 = Debug|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x64.ActiveCfg = Debug|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x64.Build.0 = Debug|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x64.Deploy.0 = Debug|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x86.ActiveCfg = Debug|Win32
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x86.Build.0 = Debug|Win32
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Debug|x86.Deploy.0 = Debug|Win32
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|ARM.ActiveCfg = Release|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|ARM.Build.0 = Release|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|ARM.Deploy.0 = Release|ARM
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x64.ActiveCfg = Release|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x64.Build.0 = Release|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x64.Deploy.0 = Release|x64
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x86.ActiveCfg = Release|Win32
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x86.Build.0 = Release|Win32
+ {7134432A-49F2-4DC7-8F72-06F873A683EC}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {58EFB63D-FFA2-4263-AE6A-6764E4E04CCA}
+ EndGlobalSection
+EndGlobal
diff --git a/support/hololens/ServoApp.vcxproj b/support/hololens/ServoApp.vcxproj
new file mode 100644
index 00000000000..09ff575368a
--- /dev/null
+++ b/support/hololens/ServoApp.vcxproj
@@ -0,0 +1,436 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+
+ {7134432a-49f2-4dc7-8f72-06f873a683ec}
+ hlservo
+ en-US
+ 14.0
+ true
+ Windows Store
+ 10.0
+ 10.0.17763.0
+ 10.0.17763.0
+ ServoApp
+
+
+
+ Application
+ true
+ v141
+
+
+ Application
+ false
+ true
+ v141
+
+
+
+
+
+
+
+
+ 14E8C17B8F0E474455725DAA105238215838FEB1
+ ServoApp_TemporaryKey.pfx
+
+
+
+ incore.lib;%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm
+
+
+
+
+ mincore.lib;%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib
+
+
+
+
+ mincore.lib;simpleservo.dll.lib;%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories);$(VCInstallDir)\lib\store\amd64;$(VCInstallDir)\lib\amd64;$(ProjectDir)\..\..\target\debug
+
+
+
+
+ mincore.lib;simpleservo.dll.lib;%(AdditionalDependencies)
+ %(AdditionalLibraryDirectories);$(VCInstallDir)\lib\store\amd64;$(VCInstallDir)\lib\amd64;$(ProjectDir)\..\..\target\release
+
+
+
+
+ pch.h
+ $(IntDir)pch.pch
+ $(ProjectDir)\..\..\target\debug\;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories)
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ pch.h
+ $(IntDir)pch.pch
+ $(ProjectDir)\..\..\target\release\;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories)
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+ App.xaml
+
+
+ OpenGLESPage.xaml
+
+
+
+
+ App.xaml
+
+
+ OpenGLESPage.xaml
+
+
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+ true
+ false
+ true
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
diff --git a/support/hololens/ServoApp.vcxproj.filters b/support/hololens/ServoApp.vcxproj.filters
new file mode 100644
index 00000000000..13b7c033ae1
--- /dev/null
+++ b/support/hololens/ServoApp.vcxproj.filters
@@ -0,0 +1,245 @@
+
+
+
+
+ src
+
+
+ src
+
+
+ src
+
+
+
+
+
+
+ src
+
+
+ src
+
+
+ src
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsDebug
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+ ServoDLLsRelease
+
+
+
+
+ {f663883d-5302-4e09-82e3-094b0a4fa9bc}
+
+
+ {45140811-c74b-4497-ba07-a7610fe2fef9}
+
+
+ {851a4628-484c-4859-bb9b-3153914487f5}
+
+
+ {96a56d11-301b-46ec-b081-50010b467ebf}
+
+
+
+
+ src
+
+
+
+
+ src
+
+
+
\ No newline at end of file
diff --git a/support/hololens/ServoApp_TemporaryKey.pfx b/support/hololens/ServoApp_TemporaryKey.pfx
new file mode 100644
index 00000000000..81aa780ceeb
Binary files /dev/null and b/support/hololens/ServoApp_TemporaryKey.pfx differ
diff --git a/support/hololens/packages.config b/support/hololens/packages.config
new file mode 100644
index 00000000000..70c3dea0e70
--- /dev/null
+++ b/support/hololens/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/support/hololens/pch.cpp b/support/hololens/pch.cpp
new file mode 100644
index 00000000000..4c80ac1ff7e
--- /dev/null
+++ b/support/hololens/pch.cpp
@@ -0,0 +1,5 @@
+/* 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"
diff --git a/support/hololens/pch.h b/support/hololens/pch.h
new file mode 100644
index 00000000000..f2ebe741294
--- /dev/null
+++ b/support/hololens/pch.h
@@ -0,0 +1,19 @@
+/* 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/. */
+
+#pragma once
+
+#include
+#include
+
+#define GL_GLEXT_PROTOTYPES
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include