mirror of https://github.com/bjornbytes/lovr.git
Add lovr.headset.isPassthroughEnabled and lovr.headset.setPassthroughEnabled;
This commit is contained in:
parent
5a27a0f819
commit
89edccbf4c
18
etc/webxr.js
18
etc/webxr.js
|
@ -182,6 +182,11 @@ var webxr = {
|
|||
return 1; /* ORIGIN_FLOOR */
|
||||
},
|
||||
|
||||
webxr_getDisplayDimensions: function(width, height) {
|
||||
HEAPU32[width >> 2] = state.layer.framebufferWidth;
|
||||
HEAPU32[height >> 2] = state.layer.framebufferHeight;
|
||||
},
|
||||
|
||||
webxr_getDisplayTime: function() {
|
||||
return state.displayTime / 1000.0;
|
||||
},
|
||||
|
@ -190,11 +195,6 @@ var webxr = {
|
|||
return (state.displayTime - state.lastDisplayTime) / 1000.0;
|
||||
},
|
||||
|
||||
webxr_getDisplayDimensions: function(width, height) {
|
||||
HEAPU32[width >> 2] = state.layer.framebufferWidth;
|
||||
HEAPU32[height >> 2] = state.layer.framebufferHeight;
|
||||
},
|
||||
|
||||
webxr_getDisplayFrequency: function() {
|
||||
return 0.0;
|
||||
},
|
||||
|
@ -411,6 +411,14 @@ var webxr = {
|
|||
return true;
|
||||
},
|
||||
|
||||
webxr_isPassthroughEnabled: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
webxr_setPassthroughEnabled: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
webxr_update: function() {
|
||||
return (state.displayTime - state.lastDisplayTime) / 1000.0;
|
||||
}
|
||||
|
|
|
@ -539,6 +539,18 @@ static int l_lovrHeadsetIsFocused(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrHeadsetIsPassthroughEnabled(lua_State* L) {
|
||||
lua_pushboolean(L, lovrHeadsetInterface->isPassthroughEnabled());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrHeadsetSetPassthroughEnabled(lua_State* L) {
|
||||
bool enable = lua_toboolean(L, 1);
|
||||
bool success = lovrHeadsetInterface->setPassthroughEnabled(enable);
|
||||
lua_pushboolean(L, success);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrHeadsetUpdate(lua_State* L) {
|
||||
double dt = 0.;
|
||||
|
||||
|
@ -620,6 +632,8 @@ static const luaL_Reg lovrHeadset[] = {
|
|||
{ "getPass", l_lovrHeadsetGetPass },
|
||||
{ "submit", l_lovrHeadsetSubmit },
|
||||
{ "isFocused", l_lovrHeadsetIsFocused },
|
||||
{ "isPassthroughEnabled", l_lovrHeadsetIsPassthroughEnabled },
|
||||
{ "setPassthroughEnabled", l_lovrHeadsetSetPassthroughEnabled },
|
||||
{ "update", l_lovrHeadsetUpdate },
|
||||
{ "getTime", l_lovrHeadsetGetTime },
|
||||
{ "getDeltaTime", l_lovrHeadsetGetDeltaTime },
|
||||
|
|
|
@ -155,6 +155,8 @@ typedef struct HeadsetInterface {
|
|||
struct Pass* (*getPass)(void);
|
||||
void (*submit)(void);
|
||||
bool (*isFocused)(void);
|
||||
bool (*isPassthroughEnabled)(void);
|
||||
bool (*setPassthroughEnabled)(bool enable);
|
||||
double (*update)(void);
|
||||
} HeadsetInterface;
|
||||
|
||||
|
|
|
@ -75,6 +75,10 @@ static HeadsetOrigin desktop_getOriginType(void) {
|
|||
return ORIGIN_HEAD;
|
||||
}
|
||||
|
||||
static void desktop_getDisplayDimensions(uint32_t* width, uint32_t* height) {
|
||||
os_window_get_size(width, height);
|
||||
}
|
||||
|
||||
static double desktop_getDisplayTime(void) {
|
||||
return state.nextDisplayTime - state.epoch;
|
||||
}
|
||||
|
@ -83,10 +87,6 @@ static double desktop_getDeltaTime(void) {
|
|||
return state.nextDisplayTime - state.prevDisplayTime;
|
||||
}
|
||||
|
||||
static void desktop_getDisplayDimensions(uint32_t* width, uint32_t* height) {
|
||||
os_window_get_size(width, height);
|
||||
}
|
||||
|
||||
static uint32_t desktop_getViewCount(void) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -225,6 +225,14 @@ static bool desktop_isFocused(void) {
|
|||
return state.focused;
|
||||
}
|
||||
|
||||
static bool desktop_isPassthroughEnabled(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool desktop_setPassthroughEnabled(bool enable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static double desktop_update(void) {
|
||||
bool front = os_is_key_down(KEY_W) || os_is_key_down(KEY_UP);
|
||||
bool back = os_is_key_down(KEY_S) || os_is_key_down(KEY_DOWN);
|
||||
|
@ -325,9 +333,9 @@ HeadsetInterface lovrHeadsetDesktopDriver = {
|
|||
.destroy = desktop_destroy,
|
||||
.getName = desktop_getName,
|
||||
.getOriginType = desktop_getOriginType,
|
||||
.getDisplayDimensions = desktop_getDisplayDimensions,
|
||||
.getDisplayTime = desktop_getDisplayTime,
|
||||
.getDeltaTime = desktop_getDeltaTime,
|
||||
.getDisplayDimensions = desktop_getDisplayDimensions,
|
||||
.getViewCount = desktop_getViewCount,
|
||||
.getViewPose = desktop_getViewPose,
|
||||
.getViewAngles = desktop_getViewAngles,
|
||||
|
@ -348,5 +356,7 @@ HeadsetInterface lovrHeadsetDesktopDriver = {
|
|||
.getPass = desktop_getPass,
|
||||
.submit = desktop_submit,
|
||||
.isFocused = desktop_isFocused,
|
||||
.isPassthroughEnabled = desktop_isPassthroughEnabled,
|
||||
.setPassthroughEnabled = desktop_setPassthroughEnabled,
|
||||
.update = desktop_update
|
||||
};
|
||||
|
|
|
@ -98,7 +98,13 @@ uintptr_t gpu_vk_get_queue(uint32_t* queueFamilyIndex, uint32_t* queueIndex);
|
|||
X(xrEnumerateDisplayRefreshRatesFB)\
|
||||
X(xrRequestDisplayRefreshRateFB)\
|
||||
X(xrQuerySystemTrackedKeyboardFB)\
|
||||
X(xrCreateKeyboardSpaceFB)
|
||||
X(xrCreateKeyboardSpaceFB)\
|
||||
X(xrCreatePassthroughFB)\
|
||||
X(xrDestroyPassthroughFB)\
|
||||
X(xrPassthroughStartFB)\
|
||||
X(xrPassthroughPauseFB)\
|
||||
X(xrCreatePassthroughLayerFB)\
|
||||
X(xrDestroyPassthroughLayerFB)
|
||||
|
||||
#define XR_DECLARE(fn) static PFN_##fn fn;
|
||||
#define XR_LOAD(fn) xrGetInstanceProcAddr(state.instance, #fn, (PFN_xrVoidFunction*) &fn);
|
||||
|
@ -156,6 +162,7 @@ static struct {
|
|||
XrCompositionLayerProjection layers[1];
|
||||
XrCompositionLayerProjectionView layerViews[2];
|
||||
XrCompositionLayerDepthInfoKHR depthInfo[2];
|
||||
XrCompositionLayerPassthroughFB passthroughLayer;
|
||||
XrFrameState frameState;
|
||||
TextureFormat depthFormat;
|
||||
Texture* textures[2][MAX_IMAGES];
|
||||
|
@ -174,6 +181,9 @@ static struct {
|
|||
XrPath actionFilters[MAX_DEVICES];
|
||||
XrHandTrackerEXT handTrackers[2];
|
||||
XrControllerModelKeyMSFT controllerModelKeys[2];
|
||||
XrPassthroughFB passthrough;
|
||||
XrPassthroughLayerFB passthroughLayerHandle;
|
||||
bool passthroughActive;
|
||||
struct {
|
||||
bool controllerModel;
|
||||
bool depth;
|
||||
|
@ -185,6 +195,7 @@ static struct {
|
|||
bool headless;
|
||||
bool keyboardTracking;
|
||||
bool overlay;
|
||||
bool passthrough;
|
||||
bool refreshRate;
|
||||
bool viveTrackers;
|
||||
} features;
|
||||
|
@ -371,6 +382,7 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
{ "XR_FB_hand_tracking_aim", &state.features.handTrackingAim, true },
|
||||
{ "XR_FB_hand_tracking_mesh", &state.features.handTrackingMesh, true },
|
||||
{ "XR_FB_keyboard_tracking", &state.features.keyboardTracking, true },
|
||||
{ "XR_FB_passthrough", &state.features.passthrough, true },
|
||||
{ "XR_MND_headless", &state.features.headless, true },
|
||||
{ "XR_MSFT_controller_model", &state.features.controllerModel, true },
|
||||
{ "XR_ULTRALEAP_hand_tracking_forearm", &state.features.handTrackingElbow, true },
|
||||
|
@ -413,24 +425,11 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
|
||||
XR_INIT(xrGetSystem(state.instance, &info, &state.system));
|
||||
|
||||
XrSystemEyeGazeInteractionPropertiesEXT eyeGazeProperties = {
|
||||
.type = XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT,
|
||||
.supportsEyeGazeInteraction = false
|
||||
};
|
||||
|
||||
XrSystemHandTrackingPropertiesEXT handTrackingProperties = {
|
||||
.type = XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT,
|
||||
.supportsHandTracking = false
|
||||
};
|
||||
|
||||
XrSystemKeyboardTrackingPropertiesFB keyboardTrackingProperties = {
|
||||
.type = XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB,
|
||||
.supportsKeyboardTracking = false
|
||||
};
|
||||
|
||||
XrSystemProperties properties = {
|
||||
.type = XR_TYPE_SYSTEM_PROPERTIES
|
||||
};
|
||||
XrSystemEyeGazeInteractionPropertiesEXT eyeGazeProperties = { .type = XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT };
|
||||
XrSystemHandTrackingPropertiesEXT handTrackingProperties = { .type = XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT };
|
||||
XrSystemKeyboardTrackingPropertiesFB keyboardTrackingProperties = { .type = XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB };
|
||||
XrSystemPassthroughProperties2FB passthroughProperties = { .type = XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB };
|
||||
XrSystemProperties properties = { .type = XR_TYPE_SYSTEM_PROPERTIES };
|
||||
|
||||
if (state.features.gaze) {
|
||||
eyeGazeProperties.next = properties.next;
|
||||
|
@ -447,10 +446,16 @@ static bool openxr_init(HeadsetConfig* config) {
|
|||
properties.next = &keyboardTrackingProperties;
|
||||
}
|
||||
|
||||
if (state.features.passthrough) {
|
||||
passthroughProperties.next = properties.next;
|
||||
properties.next = &passthroughProperties;
|
||||
}
|
||||
|
||||
XR_INIT(xrGetSystemProperties(state.instance, state.system, &properties));
|
||||
state.features.gaze = eyeGazeProperties.supportsEyeGazeInteraction;
|
||||
state.features.handTracking = handTrackingProperties.supportsHandTracking;
|
||||
state.features.keyboardTracking = keyboardTrackingProperties.supportsKeyboardTracking;
|
||||
state.features.passthrough = passthroughProperties.capabilities & XR_PASSTHROUGH_CAPABILITY_BIT_FB;
|
||||
|
||||
uint32_t viewConfigurationCount;
|
||||
XrViewConfigurationType viewConfigurations[2];
|
||||
|
@ -1042,17 +1047,10 @@ static void openxr_start(void) {
|
|||
}
|
||||
}
|
||||
|
||||
XrCompositionLayerFlags layerFlags = 0;
|
||||
|
||||
if (state.features.overlay) {
|
||||
layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
}
|
||||
|
||||
// Pre-init composition layer
|
||||
state.layers[0] = (XrCompositionLayerProjection) {
|
||||
.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION,
|
||||
.space = state.referenceSpace,
|
||||
.layerFlags = layerFlags,
|
||||
.viewCount = 2,
|
||||
.views = state.layerViews
|
||||
};
|
||||
|
@ -1122,6 +1120,9 @@ static void openxr_stop(void) {
|
|||
if (state.handTrackers[0]) xrDestroyHandTrackerEXT(state.handTrackers[0]);
|
||||
if (state.handTrackers[1]) xrDestroyHandTrackerEXT(state.handTrackers[1]);
|
||||
|
||||
if (state.passthrough) xrDestroyPassthroughFB(state.passthrough);
|
||||
if (state.passthroughLayerHandle) xrDestroyPassthroughLayerFB(state.passthroughLayerHandle);
|
||||
|
||||
for (size_t i = 0; i < MAX_DEVICES; i++) {
|
||||
if (state.spaces[i]) {
|
||||
xrDestroySpace(state.spaces[i]);
|
||||
|
@ -2055,13 +2056,13 @@ static void openxr_submit(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
XrCompositionLayerBaseHeader const* layers[2];
|
||||
|
||||
XrFrameEndInfo info = {
|
||||
.type = XR_TYPE_FRAME_END_INFO,
|
||||
.displayTime = state.frameState.predictedDisplayTime,
|
||||
.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE,
|
||||
.layers = (const XrCompositionLayerBaseHeader*[1]) {
|
||||
(XrCompositionLayerBaseHeader*) &state.layers[0]
|
||||
}
|
||||
.layers = layers
|
||||
};
|
||||
|
||||
if (state.features.depth) {
|
||||
|
@ -2081,7 +2082,20 @@ static void openxr_submit(void) {
|
|||
XR(xrReleaseSwapchainImage(state.swapchain[DEPTH], NULL));
|
||||
}
|
||||
|
||||
info.layerCount = 1;
|
||||
if (state.passthroughActive) {
|
||||
layers[0] = (const XrCompositionLayerBaseHeader*) &state.passthroughLayer;
|
||||
layers[1] = (const XrCompositionLayerBaseHeader*) &state.layers[0];
|
||||
info.layerCount = 2;
|
||||
} else {
|
||||
layers[0] = (const XrCompositionLayerBaseHeader*) &state.layers[0];
|
||||
info.layerCount = 1;
|
||||
}
|
||||
|
||||
if (state.features.overlay || state.passthroughActive) {
|
||||
state.layers[0].layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
} else {
|
||||
state.layers[0].layerFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
XR(xrEndFrame(state.session, &info));
|
||||
|
@ -2093,6 +2107,67 @@ static bool openxr_isFocused(void) {
|
|||
return state.sessionState == XR_SESSION_STATE_FOCUSED;
|
||||
}
|
||||
|
||||
static bool openxr_isPassthroughEnabled(void) {
|
||||
return state.passthroughActive;
|
||||
}
|
||||
|
||||
static bool openxr_setPassthroughEnabled(bool enable) {
|
||||
if (!state.features.passthrough) return false;
|
||||
|
||||
XrResult result = XR_SUCCESS;
|
||||
|
||||
if (!state.passthrough) {
|
||||
XrPassthroughCreateInfoFB info = { .type = XR_TYPE_PASSTHROUGH_CREATE_INFO_FB };
|
||||
result = xrCreatePassthroughFB(state.session, &info, &state.passthrough);
|
||||
|
||||
if (XR_FAILED(result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XrPassthroughLayerCreateInfoFB layerInfo = {
|
||||
.type = XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB,
|
||||
.passthrough = state.passthrough,
|
||||
.purpose = XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB,
|
||||
.flags = XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB
|
||||
};
|
||||
|
||||
result = xrCreatePassthroughLayerFB(state.session, &layerInfo, &state.passthroughLayerHandle);
|
||||
|
||||
if (XR_FAILED(result)) {
|
||||
xrDestroyPassthroughFB(state.passthrough);
|
||||
state.passthrough = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
state.passthroughLayer = (XrCompositionLayerPassthroughFB) {
|
||||
.type = XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB,
|
||||
.layerHandle = state.passthroughLayerHandle
|
||||
};
|
||||
}
|
||||
|
||||
if (enable == state.passthroughActive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
result = xrPassthroughStartFB(state.passthrough);
|
||||
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
state.passthroughActive = true;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
result = xrPassthroughPauseFB(state.passthrough);
|
||||
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
state.passthroughActive = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static double openxr_update(void) {
|
||||
if (state.waited) return openxr_getDeltaTime();
|
||||
|
||||
|
@ -2202,5 +2277,7 @@ HeadsetInterface lovrHeadsetOpenXRDriver = {
|
|||
.getPass = openxr_getPass,
|
||||
.submit = openxr_submit,
|
||||
.isFocused = openxr_isFocused,
|
||||
.isPassthroughEnabled = openxr_isPassthroughEnabled,
|
||||
.setPassthroughEnabled = openxr_setPassthroughEnabled,
|
||||
.update = openxr_update
|
||||
};
|
||||
|
|
|
@ -5,9 +5,9 @@ extern void webxr_start(void);
|
|||
extern void webxr_destroy(void);
|
||||
extern bool webxr_getName(char* name, size_t length);
|
||||
extern HeadsetOrigin webxr_getOriginType(void);
|
||||
extern void webxr_getDisplayDimensions(uint32_t* width, uint32_t* height);
|
||||
extern double webxr_getDisplayTime(void);
|
||||
extern double webxr_getDeltaTime(void);
|
||||
extern void webxr_getDisplayDimensions(uint32_t* width, uint32_t* height);
|
||||
extern uint32_t webxr_getViewCount(void);
|
||||
extern bool webxr_getViewPose(uint32_t view, float* position, float* orientation);
|
||||
extern bool webxr_getViewAngles(uint32_t view, float* left, float* right, float* up, float* down);
|
||||
|
@ -26,6 +26,8 @@ extern struct ModelData* webxr_newModelData(Device device, bool animated);
|
|||
extern bool webxr_animate(struct Model* model);
|
||||
extern void webxr_renderTo(void (*callback)(void*), void* userdata);
|
||||
extern bool webxr_isFocused(void);
|
||||
extern bool webxr_isPassthroughEnabled(void);
|
||||
extern bool webxr_setPassthroughEnabled(bool enable);
|
||||
extern double webxr_update(void);
|
||||
|
||||
static bool webxrAttached = false;
|
||||
|
|
Loading…
Reference in New Issue