Files
tiny_computer/android/app/src/main/cpp/xrio/renderer.c
2024-09-20 21:39:48 +08:00

566 lines
25 KiB
C

#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "engine.h"
#include "math.h"
#include "renderer.h"
#define DECL_PFN(pfn) PFN_##pfn pfn = NULL
#define INIT_PFN(pfn) OXR(xrGetInstanceProcAddr(engine->Instance, #pfn, (PFN_xrVoidFunction*)(&pfn)))
DECL_PFN(xrCreatePassthroughFB);
DECL_PFN(xrDestroyPassthroughFB);
DECL_PFN(xrPassthroughStartFB);
DECL_PFN(xrPassthroughPauseFB);
DECL_PFN(xrCreatePassthroughLayerFB);
DECL_PFN(xrDestroyPassthroughLayerFB);
DECL_PFN(xrPassthroughLayerPauseFB);
DECL_PFN(xrPassthroughLayerResumeFB);
void XrRendererInit(struct XrEngine* engine, struct XrRenderer* renderer) {
if (renderer->Initialized) {
XrRendererDestroy(engine, renderer);
}
memset(renderer, 0, sizeof(renderer));
if (engine->PlatformFlag[PLATFORM_EXTENSION_PASSTHROUGH]) {
INIT_PFN(xrCreatePassthroughFB);
INIT_PFN(xrDestroyPassthroughFB);
INIT_PFN(xrPassthroughStartFB);
INIT_PFN(xrPassthroughPauseFB);
INIT_PFN(xrCreatePassthroughLayerFB);
INIT_PFN(xrDestroyPassthroughLayerFB);
INIT_PFN(xrPassthroughLayerPauseFB);
INIT_PFN(xrPassthroughLayerResumeFB);
}
int eyeW, eyeH;
XrRendererGetResolution(engine, renderer, &eyeW, &eyeH);
renderer->ConfigInt[CONFIG_VIEWPORT_WIDTH] = eyeW;
renderer->ConfigInt[CONFIG_VIEWPORT_HEIGHT] = eyeH;
// Get the viewport configuration info for the chosen viewport configuration type.
renderer->ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
OXR(xrGetViewConfigurationProperties(engine->Instance, engine->SystemId,
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
&renderer->ViewportConfig));
uint32_t num_spaces = 0;
OXR(xrEnumerateReferenceSpaces(engine->Session, 0, &num_spaces, NULL));
XrReferenceSpaceType* spaces = (XrReferenceSpaceType*)malloc(num_spaces * sizeof(XrReferenceSpaceType));
OXR(xrEnumerateReferenceSpaces(engine->Session, num_spaces, &num_spaces, spaces));
for (uint32_t i = 0; i < num_spaces; i++) {
if (spaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
renderer->StageSupported = true;
break;
}
}
free(spaces);
if (engine->CurrentSpace == XR_NULL_HANDLE) {
XrRendererRecenter(engine, renderer);
}
renderer->Projections = (XrView*)(malloc(XrMaxNumEyes * sizeof(XrView)));
for (int eye = 0; eye < XrMaxNumEyes; eye++) {
memset(&renderer->Projections[eye], 0, sizeof(XrView));
renderer->Projections[eye].type = XR_TYPE_VIEW;
}
// Create framebuffers.
int width = renderer->ViewConfig[0].recommendedImageRectWidth;
int height = renderer->ViewConfig[0].recommendedImageRectHeight;
for (int i = 0; i < XrMaxNumEyes; i++) {
XrFramebufferCreate(&renderer->Framebuffer[i], engine->Session, width, height);
}
if (engine->PlatformFlag[PLATFORM_EXTENSION_PASSTHROUGH]) {
XrPassthroughCreateInfoFB ptci = {XR_TYPE_PASSTHROUGH_CREATE_INFO_FB};
XrResult result;
OXR(result = xrCreatePassthroughFB(engine->Session, &ptci, &renderer->Passthrough));
if (XR_SUCCEEDED(result)) {
XrPassthroughLayerCreateInfoFB plci = {XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB};
plci.passthrough = renderer->Passthrough;
plci.purpose = XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB;
OXR(xrCreatePassthroughLayerFB(engine->Session, &plci, &renderer->PassthroughLayer));
}
OXR(xrPassthroughStartFB(renderer->Passthrough));
OXR(xrPassthroughLayerResumeFB(renderer->PassthroughLayer));
}
renderer->Initialized = true;
}
void XrRendererDestroy(struct XrEngine* engine, struct XrRenderer* renderer) {
if (!renderer->Initialized) {
return;
}
if (engine->PlatformFlag[PLATFORM_EXTENSION_PASSTHROUGH]) {
if (renderer->PassthroughRunning) {
OXR(xrPassthroughLayerPauseFB(renderer->PassthroughLayer));
}
OXR(xrPassthroughPauseFB(renderer->Passthrough));
OXR(xrDestroyPassthroughFB(renderer->Passthrough));
renderer->Passthrough = XR_NULL_HANDLE;
}
for (int i = 0; i < XrMaxNumEyes; i++) {
XrFramebufferDestroy(&renderer->Framebuffer[i]);
}
free(renderer->Projections);
renderer->Initialized = false;
}
void XrRendererGetResolution(struct XrEngine* engine, struct XrRenderer* renderer, int* pWidth, int* pHeight) {
static int width = 0;
static int height = 0;
if (engine) {
// Enumerate the viewport configurations.
uint32_t viewport_config_count = 0;
OXR(xrEnumerateViewConfigurations(engine->Instance, engine->SystemId, 0,
&viewport_config_count, NULL));
XrViewConfigurationType* viewport_configs =
(XrViewConfigurationType*)malloc(viewport_config_count * sizeof(XrViewConfigurationType));
OXR(xrEnumerateViewConfigurations(engine->Instance, engine->SystemId,
viewport_config_count, &viewport_config_count,
viewport_configs));
for (uint32_t i = 0; i < viewport_config_count; i++) {
const XrViewConfigurationType viewport_config_type = viewport_configs[i];
ALOGV("Viewport configuration type %d", (int)viewport_config_type);
XrViewConfigurationProperties viewport_config;
viewport_config.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
OXR(xrGetViewConfigurationProperties(engine->Instance, engine->SystemId,
viewport_config_type, &viewport_config));
uint32_t view_count;
OXR(xrEnumerateViewConfigurationViews(engine->Instance, engine->SystemId,
viewport_config_type, 0, &view_count, NULL));
if (view_count > 0) {
XrViewConfigurationView* elements =
(XrViewConfigurationView*)malloc(view_count * sizeof(XrViewConfigurationView));
for (uint32_t e = 0; e < view_count; e++) {
elements[e].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
elements[e].next = NULL;
}
OXR(xrEnumerateViewConfigurationViews(engine->Instance, engine->SystemId,
viewport_config_type, view_count, &view_count,
elements));
// Cache the view config properties for the selected config type.
if (viewport_config_type == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO) {
assert(view_count == XrMaxNumEyes);
for (uint32_t e = 0; e < view_count; e++) {
renderer->ViewConfig[e] = elements[e];
}
}
free(elements);
} else {
ALOGE("Empty viewport configuration");
}
}
free(viewport_configs);
*pWidth = width = renderer->ViewConfig[0].recommendedImageRectWidth;
*pHeight = height = renderer->ViewConfig[0].recommendedImageRectHeight;
} else {
// use cached values
*pWidth = width;
*pHeight = height;
}
}
bool XrRendererInitFrame(struct XrEngine* engine, struct XrRenderer* renderer) {
if (!renderer->Initialized) {
return false;
}
XrRendererHandleXrEvents(engine, renderer);
if (!renderer->SessionActive) {
return false;
}
XrRendererUpdateStageBounds(engine);
// Update passthrough
if (renderer->PassthroughRunning != renderer->ConfigInt[CONFIG_PASSTHROUGH]) {
if (renderer->ConfigInt[CONFIG_PASSTHROUGH]) {
OXR(xrPassthroughLayerResumeFB(renderer->PassthroughLayer));
} else {
OXR(xrPassthroughLayerPauseFB(renderer->PassthroughLayer));
}
renderer->PassthroughRunning = renderer->ConfigInt[CONFIG_PASSTHROUGH];
}
XrEngineWaitForFrame(engine);
XrViewLocateInfo projection_info = {};
projection_info.type = XR_TYPE_VIEW_LOCATE_INFO;
projection_info.next = NULL;
projection_info.viewConfigurationType = renderer->ViewportConfig.viewConfigurationType;
projection_info.displayTime = engine->PredictedDisplayTime;
projection_info.space = engine->CurrentSpace;
XrViewState view_state = {XR_TYPE_VIEW_STATE, NULL};
uint32_t projection_capacity = XrMaxNumEyes;
uint32_t projection_count = projection_capacity;
OXR(xrLocateViews(engine->Session, &projection_info, &view_state, projection_capacity,
&projection_count, renderer->Projections));
// Get the HMD pose, predicted for the middle of the time period during which
// the new eye images will be displayed. The number of frames predicted ahead
// depends on the pipeline depth of the engine and the synthesis rate.
// The better the prediction, the less black will be pulled in at the edges.
XrFrameBeginInfo begin_frame_info = {};
begin_frame_info.type = XR_TYPE_FRAME_BEGIN_INFO;
begin_frame_info.next = NULL;
OXR(xrBeginFrame(engine->Session, &begin_frame_info));
renderer->Fov.angleLeft = 0;
renderer->Fov.angleRight = 0;
renderer->Fov.angleUp = 0;
renderer->Fov.angleDown = 0;
for (int eye = 0; eye < XrMaxNumEyes; eye++) {
renderer->Fov.angleLeft += renderer->Projections[eye].fov.angleLeft / 2.0f;
renderer->Fov.angleRight += renderer->Projections[eye].fov.angleRight / 2.0f;
renderer->Fov.angleUp += renderer->Projections[eye].fov.angleUp / 2.0f;
renderer->Fov.angleDown += renderer->Projections[eye].fov.angleDown / 2.0f;
renderer->InvertedViewPose[eye] = renderer->Projections[eye].pose;
}
renderer->HmdOrientation = XrQuaternionfEulerAngles(renderer->InvertedViewPose[0].orientation);
renderer->LayerCount = 0;
memset(renderer->Layers, 0, sizeof(XrCompositorLayer) * XrMaxLayerCount);
return true;
}
void XrRendererBeginFrame(struct XrRenderer* renderer, int fbo_index) {
renderer->ConfigInt[CONFIG_CURRENT_FBO] = fbo_index;
XrFramebufferAcquire(&renderer->Framebuffer[fbo_index]);
}
void XrRendererEndFrame(struct XrRenderer* renderer) {
int fbo_index = renderer->ConfigInt[CONFIG_CURRENT_FBO];
XrFramebufferRelease(&renderer->Framebuffer[fbo_index]);
}
void XrRendererFinishFrame(struct XrEngine* engine, struct XrRenderer* renderer) {
int x = 0;
int y = 0;
int w = renderer->Framebuffer[0].Width;
int h = renderer->Framebuffer[0].Height;
if (renderer->ConfigInt[CONFIG_SBS]) {
w /= 2;
}
int mode = renderer->ConfigInt[CONFIG_MODE];
XrCompositionLayerProjectionView projection_layer_elements[2] = {};
if ((mode == RENDER_MODE_MONO_6DOF) || (mode == RENDER_MODE_STEREO_6DOF)) {
renderer->ConfigFloat[CONFIG_MENU_YAW] = renderer->HmdOrientation.y;
for (int eye = 0; eye < XrMaxNumEyes; eye++) {
struct XrFramebuffer* framebuffer = &renderer->Framebuffer[0];
XrPosef pose = renderer->InvertedViewPose[0];
if (renderer->ConfigInt[CONFIG_SBS] && (eye == 1)) {
x += w;
} else if (mode != RENDER_MODE_MONO_6DOF) {
framebuffer = &renderer->Framebuffer[eye];
pose = renderer->InvertedViewPose[eye];
}
XrVector3f pitch_axis = {1, 0, 0};
XrVector3f yaw_axis = {0, 1, 0};
XrVector3f rotation = XrQuaternionfEulerAngles(pose.orientation);
XrQuaternionf pitch = XrQuaternionfCreateFromVectorAngle(pitch_axis, -ToRadians(rotation.x));
XrQuaternionf yaw = XrQuaternionfCreateFromVectorAngle(yaw_axis, ToRadians(rotation.y));
pose.orientation = XrQuaternionfMultiply(pitch, yaw);
memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView));
projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
projection_layer_elements[eye].pose = pose;
projection_layer_elements[eye].fov = renderer->Fov;
memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage));
projection_layer_elements[eye].subImage.swapchain = framebuffer->Handle;
projection_layer_elements[eye].subImage.imageRect.offset.x = x;
projection_layer_elements[eye].subImage.imageRect.offset.y = y;
projection_layer_elements[eye].subImage.imageRect.extent.width = w;
projection_layer_elements[eye].subImage.imageRect.extent.height = h;
projection_layer_elements[eye].subImage.imageArrayIndex = 0;
}
XrCompositionLayerProjection projection_layer = {};
projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
projection_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
projection_layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
projection_layer.space = engine->CurrentSpace;
projection_layer.viewCount = XrMaxNumEyes;
projection_layer.views = projection_layer_elements;
renderer->Layers[renderer->LayerCount++].projection = projection_layer;
} else if ((mode == RENDER_MODE_MONO_SCREEN) || (mode == RENDER_MODE_STEREO_SCREEN)) {
// Flat screen pose
float distance = renderer->ConfigFloat[CONFIG_CANVAS_DISTANCE];
float menu_pitch = ToRadians(renderer->ConfigFloat[CONFIG_MENU_PITCH]);
float menu_yaw = ToRadians(renderer->ConfigFloat[CONFIG_MENU_YAW]);
XrVector3f pos = {renderer->InvertedViewPose[0].position.x - sinf(menu_yaw) * cosf(menu_pitch) * distance,
renderer->InvertedViewPose[0].position.y - sinf(menu_pitch) * distance,
renderer->InvertedViewPose[0].position.z - cosf(menu_yaw) * cosf(menu_pitch) * distance};
XrVector3f pitch_axis = {1, 0, 0};
XrVector3f yaw_axis = {0, 1, 0};
XrQuaternionf pitch = XrQuaternionfCreateFromVectorAngle(pitch_axis, -menu_pitch);
XrQuaternionf yaw = XrQuaternionfCreateFromVectorAngle(yaw_axis, menu_yaw);
// Setup quad layer
struct XrFramebuffer* framebuffer = &renderer->Framebuffer[0];
XrCompositionLayerQuad quad_layer = {};
quad_layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
quad_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
quad_layer.space = engine->CurrentSpace;
memset(&quad_layer.subImage, 0, sizeof(XrSwapchainSubImage));
quad_layer.subImage.imageRect.offset.x = x;
quad_layer.subImage.imageRect.offset.y = y;
quad_layer.subImage.imageRect.extent.width = w;
quad_layer.subImage.imageRect.extent.height = h;
quad_layer.subImage.swapchain = framebuffer->Handle;
quad_layer.subImage.imageArrayIndex = 0;
quad_layer.pose.orientation = XrQuaternionfMultiply(pitch, yaw);
quad_layer.pose.position = pos;
quad_layer.size.width = 4;
quad_layer.size.height = 4;
// Build the cylinder layer
if (renderer->ConfigInt[CONFIG_SBS]) {
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT;
renderer->Layers[renderer->LayerCount++].quad = quad_layer;
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT;
quad_layer.subImage.imageRect.offset.x = w;
renderer->Layers[renderer->LayerCount++].quad = quad_layer;
} else if (mode == RENDER_MODE_MONO_SCREEN) {
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
renderer->Layers[renderer->LayerCount++].quad = quad_layer;
} else {
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT;
renderer->Layers[renderer->LayerCount++].quad = quad_layer;
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT;
quad_layer.subImage.swapchain = renderer->Framebuffer[1].Handle;
renderer->Layers[renderer->LayerCount++].quad = quad_layer;
}
} else {
assert(false);
}
// Compose the layers for this frame.
const XrCompositionLayerBaseHeader* layers[XrMaxLayerCount] = {};
for (int i = 0; i < renderer->LayerCount; i++) {
layers[i] = (const XrCompositionLayerBaseHeader*)&renderer->Layers[i];
}
XrFrameEndInfo end_frame_info = {};
end_frame_info.type = XR_TYPE_FRAME_END_INFO;
end_frame_info.displayTime = engine->PredictedDisplayTime;
end_frame_info.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
end_frame_info.layerCount = renderer->LayerCount;
end_frame_info.layers = layers;
OXR(xrEndFrame(engine->Session, &end_frame_info));
}
void XrRendererBindFramebuffer(struct XrRenderer* renderer) {
if (!renderer->Initialized)
return;
int fbo_index = renderer->ConfigInt[CONFIG_CURRENT_FBO];
XrFramebufferSetCurrent(&renderer->Framebuffer[fbo_index]);
}
void XrRendererRecenter(struct XrEngine* engine, struct XrRenderer* renderer) {
// Calculate recenter reference
XrReferenceSpaceCreateInfo space_info = {};
space_info.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
space_info.poseInReferenceSpace.orientation.w = 1.0f;
if (engine->CurrentSpace != XR_NULL_HANDLE) {
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(engine->HeadSpace, engine->CurrentSpace,
engine->PredictedDisplayTime, &loc));
renderer->HmdOrientation = XrQuaternionfEulerAngles(loc.pose.orientation);
renderer->ConfigFloat[CONFIG_RECENTER_YAW] += renderer->HmdOrientation.y;
float renceter_yaw = ToRadians(renderer->ConfigFloat[CONFIG_RECENTER_YAW]);
space_info.poseInReferenceSpace.orientation.x = 0;
space_info.poseInReferenceSpace.orientation.y = sinf(renceter_yaw / 2);
space_info.poseInReferenceSpace.orientation.z = 0;
space_info.poseInReferenceSpace.orientation.w = cosf(renceter_yaw / 2);
}
// Delete previous space instances
if (engine->StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->StageSpace));
}
if (engine->FakeSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->FakeSpace));
}
// Create a default stage space to use if SPACE_TYPE_STAGE is not
// supported, or calls to xrGetReferenceSpaceBoundsRect fail.
space_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
if (engine->PlatformFlag[PLATFORM_TRACKING_FLOOR]) {
space_info.poseInReferenceSpace.position.y = -1.6750f;
}
OXR(xrCreateReferenceSpace(engine->Session, &space_info, &engine->FakeSpace));
ALOGV("Created fake stage space from local space with offset");
engine->CurrentSpace = engine->FakeSpace;
if (renderer->StageSupported) {
space_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
space_info.poseInReferenceSpace.position.y = 0.0;
OXR(xrCreateReferenceSpace(engine->Session, &space_info, &engine->StageSpace));
ALOGV("Created stage space");
if (engine->PlatformFlag[PLATFORM_TRACKING_FLOOR]) {
engine->CurrentSpace = engine->StageSpace;
}
}
// Update menu orientation
renderer->ConfigFloat[CONFIG_MENU_PITCH] = renderer->HmdOrientation.x;
renderer->ConfigFloat[CONFIG_MENU_YAW] = 0.0f;
}
void XrRendererHandleSessionStateChanges(struct XrEngine* engine, struct XrRenderer* renderer, XrSessionState state) {
if (state == XR_SESSION_STATE_READY) {
assert(renderer->SessionActive == false);
XrSessionBeginInfo session_begin_info;
memset(&session_begin_info, 0, sizeof(session_begin_info));
session_begin_info.type = XR_TYPE_SESSION_BEGIN_INFO;
session_begin_info.next = NULL;
session_begin_info.primaryViewConfigurationType = renderer->ViewportConfig.viewConfigurationType;
XrResult result;
OXR(result = xrBeginSession(engine->Session, &session_begin_info));
renderer->SessionActive = (result == XR_SUCCESS);
ALOGV("Session active = %d", renderer->SessionActive);
#ifdef ANDROID
if (renderer->SessionActive && engine->PlatformFlag[PLATFORM_EXTENSION_PERFORMANCE]) {
PFN_xrPerfSettingsSetPerformanceLevelEXT pfnPerfSettingsSetPerformanceLevelEXT = NULL;
OXR(xrGetInstanceProcAddr(engine->Instance, "xrPerfSettingsSetPerformanceLevelEXT",
(PFN_xrVoidFunction*)(&pfnPerfSettingsSetPerformanceLevelEXT)));
OXR(pfnPerfSettingsSetPerformanceLevelEXT(
engine->Session, XR_PERF_SETTINGS_DOMAIN_CPU_EXT, XR_PERF_SETTINGS_LEVEL_BOOST_EXT));
OXR(pfnPerfSettingsSetPerformanceLevelEXT(
engine->Session, XR_PERF_SETTINGS_DOMAIN_GPU_EXT, XR_PERF_SETTINGS_LEVEL_BOOST_EXT));
PFN_xrSetAndroidApplicationThreadKHR pfnSetAndroidApplicationThreadKHR = NULL;
OXR(xrGetInstanceProcAddr(engine->Instance, "xrSetAndroidApplicationThreadKHR",
(PFN_xrVoidFunction*)(&pfnSetAndroidApplicationThreadKHR)));
OXR(pfnSetAndroidApplicationThreadKHR(engine->Session,
XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR,
engine->MainThreadId));
OXR(pfnSetAndroidApplicationThreadKHR(engine->Session,
XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR,
engine->RenderThreadId));
}
#endif
} else if (state == XR_SESSION_STATE_STOPPING) {
assert(renderer->SessionActive);
OXR(xrEndSession(engine->Session));
renderer->SessionActive = false;
}
}
void XrRendererHandleXrEvents(struct XrEngine* engine, struct XrRenderer* renderer) {
XrEventDataBuffer event_data_bufer = {};
// Poll for events
for (;;) {
XrEventDataBaseHeader* base_event_handler = (XrEventDataBaseHeader*)(&event_data_bufer);
base_event_handler->type = XR_TYPE_EVENT_DATA_BUFFER;
base_event_handler->next = NULL;
XrResult r;
OXR(r = xrPollEvent(engine->Instance, &event_data_bufer));
if (r != XR_SUCCESS) {
break;
}
switch (base_event_handler->type) {
case XR_TYPE_EVENT_DATA_EVENTS_LOST:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_EVENTS_LOST");
break;
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
{
const XrEventDataInstanceLossPending* instance_loss_pending_event =
(XrEventDataInstanceLossPending*)(base_event_handler);
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: time %lf",
FromXrTime(instance_loss_pending_event->lossTime));
}
break;
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED");
break;
case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT:
break;
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
XrRendererRecenter(engine, renderer);
break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
{
const XrEventDataSessionStateChanged* session_state_changed_event =
(XrEventDataSessionStateChanged*)(base_event_handler);
switch (session_state_changed_event->state) {
case XR_SESSION_STATE_FOCUSED:
renderer->SessionFocused = true;
break;
case XR_SESSION_STATE_VISIBLE:
renderer->SessionFocused = false;
break;
case XR_SESSION_STATE_READY:
case XR_SESSION_STATE_STOPPING:
XrRendererHandleSessionStateChanges(engine, renderer, session_state_changed_event->state);
break;
default:
break;
}
break;
}
default:
ALOGV("xrPollEvent: Unknown event");
break;
}
}
}
void XrRendererUpdateStageBounds(struct XrEngine* engine) {
XrExtent2Df stage_bounds = {};
XrResult result;
OXR(result = xrGetReferenceSpaceBoundsRect(engine->Session, XR_REFERENCE_SPACE_TYPE_STAGE,
&stage_bounds));
if (result != XR_SUCCESS) {
stage_bounds.width = 1.0f;
stage_bounds.height = 1.0f;
engine->CurrentSpace = engine->FakeSpace;
}
}