mirror of
https://github.com/servo/servo.git
synced 2025-08-11 16:35:33 +01:00
Add Servo3D immersive demo for magicleap
This commit is contained in:
parent
e381cebeb6
commit
0b48ff496f
20 changed files with 454 additions and 77 deletions
|
@ -66,7 +66,7 @@ void keyboard(Servo2D* app, bool visible) {
|
|||
}
|
||||
|
||||
// The functions Servo provides for hooking up to the ML.
|
||||
extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay,
|
||||
extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay, bool landscape,
|
||||
Servo2D*, MLLogger, MLHistoryUpdate, MLURLUpdate, MLKeyboard,
|
||||
const char* url, const char* args, int width, int height, float hidpi);
|
||||
extern "C" void heartbeat_servo(ServoInstance*);
|
||||
|
@ -174,7 +174,9 @@ int Servo2D::init() {
|
|||
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// Hook into servo
|
||||
servo_ = init_servo(ctx, surf, dpy, this, logger, history, url, keyboard, uri_, args_, VIEWPORT_W, VIEWPORT_H, HIDPI);
|
||||
servo_ = init_servo(ctx, surf, dpy, true,
|
||||
this, logger, history, url, keyboard, uri_, args_,
|
||||
VIEWPORT_W, VIEWPORT_H, HIDPI);
|
||||
if (!servo_) {
|
||||
ML_LOG(Error, "Servo2D Failed to init servo instance");
|
||||
abort();
|
||||
|
|
257
support/magicleap/Servo3D/Servo3D.cpp
Normal file
257
support/magicleap/Servo3D/Servo3D.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
/* 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/. */
|
||||
|
||||
// The immersive mode Servo magicleap demo
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#ifndef EGL_EGLEXT_PROTOTYPES
|
||||
#define EGL_EGLEXT_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
|
||||
#include <ml_graphics.h>
|
||||
#include <ml_head_tracking.h>
|
||||
#include <ml_perception.h>
|
||||
#include <ml_fileinfo.h>
|
||||
#include <ml_lifecycle.h>
|
||||
#include <ml_logging.h>
|
||||
#include <ml_privileges.h>
|
||||
|
||||
// Constants
|
||||
const char application_name[] = "com.mozilla.servo3d";
|
||||
|
||||
// A function which calls the ML logger, suitable for passing into Servo
|
||||
typedef void (*MLLogger)(MLLogLevel lvl, char* msg);
|
||||
void logger(MLLogLevel lvl, char* msg) {
|
||||
if (MLLoggingLogLevelIsEnabled(lvl)) {
|
||||
MLLoggingLog(lvl, "Servo3D", msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Entry points to servo
|
||||
typedef struct Opaque ServoInstance;
|
||||
extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay, bool landscape,
|
||||
void*, MLLogger, void*, void*, void*,
|
||||
const char* url, const char* args,
|
||||
int width, int height, float hidpi);
|
||||
extern "C" void heartbeat_servo(ServoInstance*);
|
||||
extern "C" void discard_servo(ServoInstance*);
|
||||
|
||||
// The Servo3D app
|
||||
struct Servo3D {
|
||||
ServoInstance* servo;
|
||||
bool running;
|
||||
};
|
||||
|
||||
// Callbacks
|
||||
static void onStop(void* app)
|
||||
{
|
||||
ML_LOG(Info, "%s: On stop called.", application_name);
|
||||
Servo3D* servo3d = (Servo3D*)app;
|
||||
servo3d->running = false;
|
||||
}
|
||||
|
||||
static void onPause(void* app)
|
||||
{
|
||||
ML_LOG(Info, "%s: On pause called.", application_name);
|
||||
// Treat a pause the same as a stop
|
||||
Servo3D* servo3d = (Servo3D*)app;
|
||||
servo3d->running = false;
|
||||
}
|
||||
|
||||
static void onResume(void* app)
|
||||
{
|
||||
ML_LOG(Info, "%s: On resume called.", application_name);
|
||||
}
|
||||
|
||||
static void onNewInitArg(void* app)
|
||||
{
|
||||
// TODO: call servo_navigate when a new URL arrives
|
||||
ML_LOG(Info, "%s: On new init arg called.", application_name);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// set up graphics surface
|
||||
ML_LOG(Info, "%s: Initializing EGL.", application_name);
|
||||
EGLDisplay egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
EGLint major = 4;
|
||||
EGLint minor = 0;
|
||||
eglInitialize(egl_display, &major, &minor);
|
||||
|
||||
// The GL API used should match https://github.com/servo/rust-offscreen-rendering-context/blob/fcbbb4d40dac5e969233c1519151ad5e07b7f22e/src/platform/with_egl/native_gl_context.rs#L14
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
// Should match https://github.com/servo/rust-offscreen-rendering-context/blob/fcbbb4d40dac5e969233c1519151ad5e07b7f22e/src/platform/with_egl/utils.rs#L46
|
||||
EGLint config_attribs[] = {
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_STENCIL_SIZE, 0,
|
||||
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLConfig egl_config = nullptr;
|
||||
EGLint config_size = 0;
|
||||
eglChooseConfig(egl_display, config_attribs, &egl_config, 1, &config_size);
|
||||
if (config_size < 1) {
|
||||
ML_LOG(Error, "%s: Failed to choose EGL config. (%x)", application_name, eglGetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Should match https://github.com/servo/rust-offscreen-rendering-context/blob/fcbbb4d40dac5e969233c1519151ad5e07b7f22e/src/platform/with_egl/native_gl_context.rs#L47
|
||||
EGLint context_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLContext egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs);
|
||||
if (EGL_NO_CONTEXT == egl_context) {
|
||||
ML_LOG(Error, "%s: Failed to initialize EGL context. (%x)", application_name, eglGetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
EGLint surface_attribs[] = {
|
||||
EGL_WIDTH, 1280,
|
||||
EGL_HEIGHT, 960,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLSurface egl_surface = eglCreatePbufferSurface(egl_display, egl_config, surface_attribs);
|
||||
if (EGL_NO_SURFACE == egl_surface) {
|
||||
ML_LOG(Error, "%s: Failed to initialize EGL surface. (%x)", application_name, eglGetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)) {
|
||||
ML_LOG(Error, "%s: Failed to make EGL surface current. (%x)", application_name, eglGetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLenum read_status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
|
||||
GLenum draw_status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
if ((read_status != GL_FRAMEBUFFER_COMPLETE) || (draw_status != GL_FRAMEBUFFER_COMPLETE)) {
|
||||
ML_LOG(Error, "%s: Incomplete GL framebuffer. (%x, %x)", application_name, read_status, draw_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ML_LOG(Info, "%s: Initialized EGL.", application_name);
|
||||
|
||||
// The app
|
||||
Servo3D app = { nullptr, true };
|
||||
|
||||
// let system know our app has started
|
||||
MLLifecycleCallbacks lifecycle_callbacks = {};
|
||||
lifecycle_callbacks.on_stop = onStop;
|
||||
lifecycle_callbacks.on_pause = onPause;
|
||||
lifecycle_callbacks.on_resume = onResume;
|
||||
lifecycle_callbacks.on_new_initarg = onNewInitArg;
|
||||
|
||||
if (MLResult_Ok != MLLifecycleInit(&lifecycle_callbacks, &app)) {
|
||||
ML_LOG(Error, "%s: Failed to initialize lifecycle.", application_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the file argument if there is one
|
||||
MLLifecycleInitArgList* arg_list = nullptr;
|
||||
const MLLifecycleInitArg* arg = nullptr;
|
||||
const char* url = "https://webvr.info/samples/03-vr-presentation.html";
|
||||
int64_t arg_list_len = 0;
|
||||
|
||||
if (MLResult_Ok != MLLifecycleGetInitArgList(&arg_list)) {
|
||||
ML_LOG(Error, "%s: Failed to get init args.", application_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (MLResult_Ok == MLLifecycleGetInitArgListLength(arg_list, &arg_list_len)) {
|
||||
if (arg_list_len) {
|
||||
if (MLResult_Ok != MLLifecycleGetInitArgByIndex(arg_list, 0, &arg)) {
|
||||
ML_LOG(Error, "%s: Failed to get init arg.", application_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (MLResult_Ok != MLLifecycleGetInitArgUri(arg, &url)) {
|
||||
ML_LOG(Error, "%s: Failed to get init arg uri.", application_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// init_servo calls MLLifecycleSetReadyIndication()
|
||||
|
||||
// Check privileges
|
||||
if (MLResult_Ok != MLPrivilegesStartup()) {
|
||||
ML_LOG(Error, "%s: Failed to initialize privileges.", application_name);
|
||||
return -1;
|
||||
}
|
||||
if (MLPrivilegesRequestPrivilege(MLPrivilegeID_LowLatencyLightwear) != MLPrivilegesResult_Granted) {
|
||||
ML_LOG(Error, "Privilege %d denied.", MLPrivilegeID_LowLatencyLightwear);
|
||||
return -1;
|
||||
}
|
||||
if (MLPrivilegesRequestPrivilege(MLPrivilegeID_Internet) != MLPrivilegesResult_Granted) {
|
||||
ML_LOG(Error, "Privilege %d denied.", MLPrivilegeID_Internet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// initialize perception system
|
||||
MLPerceptionSettings perception_settings;
|
||||
if (MLResult_Ok != MLPerceptionInitSettings(&perception_settings)) {
|
||||
ML_LOG(Error, "%s: Failed to initialize perception.", application_name);
|
||||
}
|
||||
|
||||
if (MLResult_Ok != MLPerceptionStartup(&perception_settings)) {
|
||||
ML_LOG(Error, "%s: Failed to startup perception.", application_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ML_LOG(Info, "%s: Initializing servo for %s.", application_name, url);
|
||||
|
||||
// Initialize servo
|
||||
app.servo = init_servo(egl_context, egl_surface, egl_display, false,
|
||||
&app, logger, nullptr, nullptr, nullptr,
|
||||
url,
|
||||
"--pref dom.webvr.enabled --pref dom.gamepad.enabled",
|
||||
500, 500, 1.0);
|
||||
|
||||
// At this point we can free the memory for the arg list, since the url isn't used after this
|
||||
MLLifecycleFreeInitArgList(&arg_list);
|
||||
|
||||
// Pin the main thread to the Denver core
|
||||
// https://forum.magicleap.com/hc/en-us/community/posts/360043120832-How-many-CPUs-does-an-immersive-app-have-access-to-
|
||||
uint32_t DenverCoreAffinityMask = 1 << 2; // Denver core is CPU2
|
||||
pid_t ThreadId = gettid();
|
||||
syscall(__NR_sched_setaffinity, ThreadId, sizeof(DenverCoreAffinityMask), &DenverCoreAffinityMask);
|
||||
|
||||
// Run the demo!
|
||||
ML_LOG(Info, "%s: Begin demo.", application_name);
|
||||
while (app.running) {
|
||||
ML_LOG(Debug, "%s: heartbeat.", application_name);
|
||||
heartbeat_servo(app.servo);
|
||||
// TODO: check heart_racing.
|
||||
}
|
||||
ML_LOG(Info, "%s: End demo.", application_name);
|
||||
|
||||
// Shut down
|
||||
discard_servo(app.servo);
|
||||
MLPerceptionShutdown();
|
||||
eglDestroyContext(egl_display, egl_context);
|
||||
eglTerminate(egl_display);
|
||||
|
||||
return 0;
|
||||
}
|
24
support/magicleap/Servo3D/Servo3D.mabu
Normal file
24
support/magicleap/Servo3D/Servo3D.mabu
Normal file
|
@ -0,0 +1,24 @@
|
|||
KIND = program
|
||||
|
||||
SRCS = \
|
||||
Servo3D.cpp
|
||||
|
||||
USES = ml_sdk
|
||||
|
||||
LIBPATHS.debug = \
|
||||
../../../target/magicleap/aarch64-linux-android/debug
|
||||
|
||||
LIBPATHS.release = \
|
||||
../../../target/magicleap/aarch64-linux-android/release
|
||||
|
||||
LIBPATHS.device = \
|
||||
$(MLSDK)/lumin/stl/libc++-lumin/lib \
|
||||
|
||||
STLIBS = \
|
||||
mlservo
|
||||
|
||||
SHLIBS = \
|
||||
c++ \
|
||||
ml_privileges \
|
||||
log \
|
||||
z
|
8
support/magicleap/Servo3D/Servo3D.package
Normal file
8
support/magicleap/Servo3D/Servo3D.package
Normal file
|
@ -0,0 +1,8 @@
|
|||
REFS = Servo3D
|
||||
|
||||
DATAS = \
|
||||
fonts.xml : etc/fonts.xml
|
||||
|
||||
# Servo SEGVs if we don't set the debuggable flag in the mpk's taildata
|
||||
# https://github.com/servo/servo/issues/22188
|
||||
OPTIONS=package/debuggable/on
|
19
support/magicleap/Servo3D/fonts.xml
Normal file
19
support/magicleap/Servo3D/fonts.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<familyset>
|
||||
<family name="sans-serif">
|
||||
<font weight="300" style="normal">/system/etc/ml/kali/Fonts/Lomino/Light/LominoUI_Lt.ttf</font>
|
||||
<font weight="300" style="italic">/system/etc/ml/kali/Fonts/Lomino/LightItalic/LominoUI_LtIt.ttf</font>
|
||||
<font weight="400" style="normal">/system/etc/ml/kali/Fonts/Lomino/Regular/LominoUI_Rg.ttf</font>
|
||||
<font weight="400" style="italic">/system/etc/ml/kali/Fonts/Lomino/Italic/LominoUI_It.ttf</font>
|
||||
<font weight="500" style="normal">/system/etc/ml/kali/Fonts/Lomino/Medium/LominoUI_Md.ttf</font>
|
||||
<font weight="500" style="italic">/system/etc/ml/kali/Fonts/Lomino/MediumItalic/LominoUI_MdIt.ttf</font>
|
||||
<font weight="700" style="normal">/system/etc/ml/kali/Fonts/Lomino/Bold/LominoUI_Bd.ttf</font>
|
||||
<font weight="700" style="italic">/system/etc/ml/kali/Fonts/Lomino/BoldItalic/LominoUI_BdIt.ttf</font>
|
||||
<font weight="900" style="normal">/system/etc/ml/kali/Fonts/Lomino/ExtraBold/LominoUI_XBd.ttf</font>
|
||||
<font weight="900" style="italic">/system/etc/ml/kali/Fonts/Lomino/ExtraBoldItalic/LominoUI_XBdIt.ttf</font>
|
||||
</family>
|
||||
|
||||
<alias name="arial" to="sans-serif" />
|
||||
<alias name="helvetica" to="sans-serif" />
|
||||
<alias name="tahoma" to="sans-serif" />
|
||||
<alias name="verdana" to="sans-serif" />
|
||||
</familyset>
|
23
support/magicleap/Servo3D/manifest.xml
Normal file
23
support/magicleap/Servo3D/manifest.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<manifest
|
||||
xmlns:ml="magicleap"
|
||||
ml:package="com.mozilla.servo3d"
|
||||
ml:version_code="1"
|
||||
ml:version_name="1.0">
|
||||
<application
|
||||
ml:visible_name="Servo3D"
|
||||
ml:sdk_version="0.20.0"
|
||||
ml:min_api_level="4">
|
||||
<component
|
||||
ml:name=".servo3d.fullscreen"
|
||||
ml:visible_name="Servo3D"
|
||||
ml:binary_name="bin/Servo3D"
|
||||
ml:type="Fullscreen">
|
||||
<icon
|
||||
ml:model_folder="Icon/Model/"
|
||||
ml:portal_folder="Icon/Portal/" />
|
||||
</component>
|
||||
<uses-privilege ml:name="ControllerPose"/>
|
||||
<uses-privilege ml:name="Internet"/>
|
||||
<uses-privilege ml:name="LowLatencyLightwear"/>
|
||||
</application>
|
||||
</manifest>
|
Loading…
Add table
Add a link
Reference in a new issue