The open source OpenXR runtime

d/android: adds support for loading cardboard calibration files

Co-authored-by: Simon Zeni <simon.zeni@collabora.com>
Co-authored-by: Rylie Pavlik <rylie.pavlik@collabora.com>
Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2560>

+454 -16
+1
.reuse/dep5
··· 138 Comment: Computer-generated files do not have a copyright per US law. 139 140 Files: src/xrt/auxiliary/android_cardboard/src/main/res/drawable/cardboard_oss_qr.png 141 Copyright: 2019 Google LLC 142 License: Apache-2.0 143 Comment: SPDX-License-Identifier missing.
··· 138 Comment: Computer-generated files do not have a copyright per US law. 139 140 Files: src/xrt/auxiliary/android_cardboard/src/main/res/drawable/cardboard_oss_qr.png 141 + src/external/cardboard/* 142 Copyright: 2019 Google LLC 143 License: Apache-2.0 144 Comment: SPDX-License-Identifier missing.
+13 -1
src/external/CMakeLists.txt
··· 1 - # Copyright 2020-2023, Collabora, Ltd. 2 # SPDX-License-Identifier: BSL-1.0 3 4 # Catch2 ··· 82 nanopb/pb_encode.h 83 ) 84 target_include_directories(xrt-external-nanopb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/nanopb) 85 86 # OpenXR 87 add_library(xrt-external-openxr INTERFACE)
··· 1 + # Copyright 2020-2025, Collabora, Ltd. 2 # SPDX-License-Identifier: BSL-1.0 3 4 # Catch2 ··· 82 nanopb/pb_encode.h 83 ) 84 target_include_directories(xrt-external-nanopb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/nanopb) 85 + 86 + if(ANDROID) 87 + add_library( 88 + xrt-external-cardboard STATIC cardboard/cardboard_device.pb.h 89 + cardboard/cardboard_device.pb.c 90 + ) 91 + 92 + target_include_directories( 93 + xrt-external-cardboard PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cardboard/ 94 + ) 95 + target_link_libraries(xrt-external-cardboard PUBLIC xrt-external-nanopb) 96 + endif() 97 98 # OpenXR 99 add_library(xrt-external-openxr INTERFACE)
+16
src/external/cardboard/cardboard_device.pb.c
···
··· 1 + /* Automatically generated nanopb constant definitions */ 2 + /* Generated by nanopb-0.4.9.1 */ 3 + 4 + #include "cardboard_device.pb.h" 5 + #if PB_PROTO_HEADER_VERSION != 40 6 + #error Regenerate this file with the current version of nanopb generator. 7 + #endif 8 + 9 + PB_BIND(cardboard_DeviceParams, cardboard_DeviceParams, AUTO) 10 + 11 + 12 + 13 + 14 + 15 + 16 +
+170
src/external/cardboard/cardboard_device.pb.h
···
··· 1 + /* Automatically generated nanopb header */ 2 + /* Generated by nanopb-0.4.9.1 */ 3 + 4 + #ifndef PB_CARDBOARD_CARDBOARD_DEVICE_PB_H_INCLUDED 5 + #define PB_CARDBOARD_CARDBOARD_DEVICE_PB_H_INCLUDED 6 + #include <pb.h> 7 + 8 + #if PB_PROTO_HEADER_VERSION != 40 9 + #error Regenerate this file with the current version of nanopb generator. 10 + #endif 11 + 12 + /* Enum definitions */ 13 + typedef enum _cardboard_DeviceParams_VerticalAlignmentType { 14 + cardboard_DeviceParams_VerticalAlignmentType_BOTTOM = 0, /* phone rests against a fixed bottom tray */ 15 + cardboard_DeviceParams_VerticalAlignmentType_CENTER = 1, /* phone screen assumed to be centered w.r.t. lenses */ 16 + cardboard_DeviceParams_VerticalAlignmentType_TOP = 2 /* phone rests against a fixed top tray */ 17 + } cardboard_DeviceParams_VerticalAlignmentType; 18 + 19 + typedef enum _cardboard_DeviceParams_ButtonType { 20 + /* No physical button, and touch screen is not easily accessible. */ 21 + cardboard_DeviceParams_ButtonType_NONE = 0, 22 + /* HMD has integrated magnet switch similar to original Cardboard. */ 23 + cardboard_DeviceParams_ButtonType_MAGNET = 1, 24 + /* At least a portion of touch screen is easily accessible to user for taps. */ 25 + cardboard_DeviceParams_ButtonType_TOUCH = 2, 26 + /* Touch screen is triggered indirectly via integrated button on the HMD. */ 27 + cardboard_DeviceParams_ButtonType_INDIRECT_TOUCH = 3 28 + } cardboard_DeviceParams_ButtonType; 29 + 30 + /* Struct definitions */ 31 + /* * 32 + Message describing properties of a VR head mount device (HMD) which uses an 33 + interchangeable smartphone as a display (e.g. Google Cardboard). 34 + 35 + While some properties are certain (e.g. inter_lens_distance), others 36 + represent nominal values which may be refined depending on context (e.g. 37 + viewport_angles). 38 + 39 + Lengths are in meters unless noted otherwise. Fields are _required_ 40 + unless noted otherwise. 41 + 42 + Some context on why this set of parameters are deemed necessary and 43 + sufficient: 44 + * FOV scale can be reasonably approximated from lens-to-screen distance 45 + and display size (i.e. knowing lens focal length isn't crucial). 46 + * Lenses are assumed to be horizontally centered with respect to 47 + display. 48 + * The display is not necessarily vertically centered. For interchangeable 49 + phones where the device rests against a tray, we can derive 50 + the vertical offset from tray-to-lens height along with phone-specific 51 + bezel and screen sizes (supplied separately). */ 52 + typedef struct _cardboard_DeviceParams { 53 + /* String identifying the device's vendor (e.g. "Google, Inc."). 54 + A device's [vendor, model] pair is expected to be globally unique. */ 55 + pb_callback_t vendor; 56 + /* String identifying the device's model, including revision info if 57 + needed (e.g. "Cardboard v1"). A device's [vendor, model] pair is 58 + expected to be globally unique. */ 59 + pb_callback_t model; 60 + /* Distance from the display screen to the optical center of lenses. 61 + This is a required field for distortion rendering, and must be positive. */ 62 + bool has_screen_to_lens_distance; 63 + float screen_to_lens_distance; 64 + /* Horizontal distance between optical center of the lenses. 65 + This is a required field for distortion rendering, and must be positive. */ 66 + bool has_inter_lens_distance; 67 + float inter_lens_distance; 68 + /* Four-element tuple (left, right, bottom, top) of left eye's view extent 69 + angles relative to center, assuming the following: 70 + * eye is aligned with optical center of lens 71 + * display screen is equal or larger than extents viewable through lens 72 + * nominal eye-to-lens distance 73 + * mirrored field of view will be applied to the right eye 74 + These values are essentially used as an optimization to avoid rendering 75 + pixels which can't be seen. 76 + This is a required field for distortion rendering, and angles must be 77 + positive. */ 78 + pb_callback_t left_eye_field_of_view_angles; 79 + /* If the phone is aligned vertically within the device by resting against 80 + a fixed top or bottom tray, this is the distance from the tray to 81 + optical center of the lenses. 82 + This is a required field for distortion rendering, and must be positive. 83 + NOTE: Due to a bug in initial versions of the SDK's, this field 84 + must be set explicitly to .035 when vertical_alignment = CENTER. */ 85 + bool has_tray_to_lens_distance; 86 + float tray_to_lens_distance; 87 + /* Coefficients Ki for pincushion distortion function which maps 88 + from position on real screen to virtual screen (i.e. texture) relative 89 + to optical center: 90 + 91 + p' = p (1 + K1 r^2 + K2 r^4 + ... + Kn r^(2n)) 92 + 93 + where r is the distance in tan-angle units from the optical center, 94 + p the input point, and p' the output point. Tan-angle units can be 95 + computed as distance on the screen divided by distance from the 96 + virtual eye to the screen. */ 97 + pb_callback_t distortion_coefficients; 98 + /* Set according to vertical alignment strategy-- see enum comments above. 99 + NOTE: If you set this to CENTER, see special instructions for the 100 + tray_to_lens_distance field below. */ 101 + bool has_vertical_alignment; 102 + cardboard_DeviceParams_VerticalAlignmentType vertical_alignment; 103 + /* Specify primary input mechanism of the HMD. Intended for advisory 104 + purposes only, to address simple questions such as "can HMD 105 + be used with apps requiring a physical button event?" or "what icon 106 + should be used to represent button action to the user?". */ 107 + bool has_primary_button; 108 + cardboard_DeviceParams_ButtonType primary_button; 109 + } cardboard_DeviceParams; 110 + 111 + 112 + #ifdef __cplusplus 113 + extern "C" { 114 + #endif 115 + 116 + /* Helper constants for enums */ 117 + #define _cardboard_DeviceParams_VerticalAlignmentType_MIN cardboard_DeviceParams_VerticalAlignmentType_BOTTOM 118 + #define _cardboard_DeviceParams_VerticalAlignmentType_MAX cardboard_DeviceParams_VerticalAlignmentType_TOP 119 + #define _cardboard_DeviceParams_VerticalAlignmentType_ARRAYSIZE ((cardboard_DeviceParams_VerticalAlignmentType)(cardboard_DeviceParams_VerticalAlignmentType_TOP+1)) 120 + 121 + #define _cardboard_DeviceParams_ButtonType_MIN cardboard_DeviceParams_ButtonType_NONE 122 + #define _cardboard_DeviceParams_ButtonType_MAX cardboard_DeviceParams_ButtonType_INDIRECT_TOUCH 123 + #define _cardboard_DeviceParams_ButtonType_ARRAYSIZE ((cardboard_DeviceParams_ButtonType)(cardboard_DeviceParams_ButtonType_INDIRECT_TOUCH+1)) 124 + 125 + #define cardboard_DeviceParams_vertical_alignment_ENUMTYPE cardboard_DeviceParams_VerticalAlignmentType 126 + #define cardboard_DeviceParams_primary_button_ENUMTYPE cardboard_DeviceParams_ButtonType 127 + 128 + 129 + /* Initializer values for message structs */ 130 + #define cardboard_DeviceParams_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, false, cardboard_DeviceParams_VerticalAlignmentType_BOTTOM, false, cardboard_DeviceParams_ButtonType_MAGNET} 131 + #define cardboard_DeviceParams_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, false, _cardboard_DeviceParams_VerticalAlignmentType_MIN, false, _cardboard_DeviceParams_ButtonType_MIN} 132 + 133 + /* Field tags (for use in manual encoding/decoding) */ 134 + #define cardboard_DeviceParams_vendor_tag 1 135 + #define cardboard_DeviceParams_model_tag 2 136 + #define cardboard_DeviceParams_screen_to_lens_distance_tag 3 137 + #define cardboard_DeviceParams_inter_lens_distance_tag 4 138 + #define cardboard_DeviceParams_left_eye_field_of_view_angles_tag 5 139 + #define cardboard_DeviceParams_tray_to_lens_distance_tag 6 140 + #define cardboard_DeviceParams_distortion_coefficients_tag 7 141 + #define cardboard_DeviceParams_vertical_alignment_tag 11 142 + #define cardboard_DeviceParams_primary_button_tag 12 143 + 144 + /* Struct field encoding specification for nanopb */ 145 + #define cardboard_DeviceParams_FIELDLIST(X, a) \ 146 + X(a, CALLBACK, OPTIONAL, STRING, vendor, 1) \ 147 + X(a, CALLBACK, OPTIONAL, STRING, model, 2) \ 148 + X(a, STATIC, OPTIONAL, FLOAT, screen_to_lens_distance, 3) \ 149 + X(a, STATIC, OPTIONAL, FLOAT, inter_lens_distance, 4) \ 150 + X(a, CALLBACK, REPEATED, FLOAT, left_eye_field_of_view_angles, 5) \ 151 + X(a, STATIC, OPTIONAL, FLOAT, tray_to_lens_distance, 6) \ 152 + X(a, CALLBACK, REPEATED, FLOAT, distortion_coefficients, 7) \ 153 + X(a, STATIC, OPTIONAL, UENUM, vertical_alignment, 11) \ 154 + X(a, STATIC, OPTIONAL, UENUM, primary_button, 12) 155 + #define cardboard_DeviceParams_CALLBACK pb_default_field_callback 156 + #define cardboard_DeviceParams_DEFAULT (const pb_byte_t*)"\x60\x01\x00" 157 + 158 + extern const pb_msgdesc_t cardboard_DeviceParams_msg; 159 + 160 + /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ 161 + #define cardboard_DeviceParams_fields &cardboard_DeviceParams_msg 162 + 163 + /* Maximum encoded size of messages (where known) */ 164 + /* cardboard_DeviceParams_size depends on runtime parameters */ 165 + 166 + #ifdef __cplusplus 167 + } /* extern "C" */ 168 + #endif 169 + 170 + #endif
+123
src/external/cardboard/cardboard_device.proto
···
··· 1 + /* 2 + * Copyright 2019 Google LLC 3 + * 4 + * Licensed under the Apache License, Version 2.0 (the "License"); 5 + * you may not use this file except in compliance with the License. 6 + * You may obtain a copy of the License at 7 + * 8 + * http://www.apache.org/licenses/LICENSE-2.0 9 + * 10 + * Unless required by applicable law or agreed to in writing, software 11 + * distributed under the License is distributed on an "AS IS" BASIS, 12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 + * See the License for the specific language governing permissions and 14 + * limitations under the License. 15 + */ 16 + syntax = "proto2"; 17 + 18 + package cardboard; 19 + 20 + option java_package = "com.google.cardboard.proto"; 21 + option java_outer_classname = "CardboardDevice"; 22 + option optimize_for = LITE_RUNTIME; 23 + 24 + /** 25 + * Message describing properties of a VR head mount device (HMD) which uses an 26 + * interchangeable smartphone as a display (e.g. Google Cardboard). 27 + * 28 + * While some properties are certain (e.g. inter_lens_distance), others 29 + * represent nominal values which may be refined depending on context (e.g. 30 + * viewport_angles). 31 + * 32 + * Lengths are in meters unless noted otherwise. Fields are _required_ 33 + * unless noted otherwise. 34 + * 35 + * Some context on why this set of parameters are deemed necessary and 36 + * sufficient: 37 + * * FOV scale can be reasonably approximated from lens-to-screen distance 38 + * and display size (i.e. knowing lens focal length isn't crucial). 39 + * * Lenses are assumed to be horizontally centered with respect to 40 + * display. 41 + * * The display is not necessarily vertically centered. For interchangeable 42 + * phones where the device rests against a tray, we can derive 43 + * the vertical offset from tray-to-lens height along with phone-specific 44 + * bezel and screen sizes (supplied separately). 45 + */ 46 + message DeviceParams { 47 + // String identifying the device's vendor (e.g. "Google, Inc."). 48 + // A device's [vendor, model] pair is expected to be globally unique. 49 + optional string vendor = 1; 50 + 51 + // String identifying the device's model, including revision info if 52 + // needed (e.g. "Cardboard v1"). A device's [vendor, model] pair is 53 + // expected to be globally unique. 54 + optional string model = 2; 55 + 56 + // Distance from the display screen to the optical center of lenses. 57 + // This is a required field for distortion rendering, and must be positive. 58 + optional float screen_to_lens_distance = 3; 59 + 60 + // Horizontal distance between optical center of the lenses. 61 + // This is a required field for distortion rendering, and must be positive. 62 + optional float inter_lens_distance = 4; 63 + 64 + // Four-element tuple (left, right, bottom, top) of left eye's view extent 65 + // angles relative to center, assuming the following: 66 + // * eye is aligned with optical center of lens 67 + // * display screen is equal or larger than extents viewable through lens 68 + // * nominal eye-to-lens distance 69 + // * mirrored field of view will be applied to the right eye 70 + // These values are essentially used as an optimization to avoid rendering 71 + // pixels which can't be seen. 72 + // This is a required field for distortion rendering, and angles must be 73 + // positive. 74 + repeated float left_eye_field_of_view_angles = 5 [packed = true]; 75 + 76 + enum VerticalAlignmentType { 77 + BOTTOM = 0; // phone rests against a fixed bottom tray 78 + CENTER = 1; // phone screen assumed to be centered w.r.t. lenses 79 + TOP = 2; // phone rests against a fixed top tray 80 + } 81 + 82 + // Set according to vertical alignment strategy-- see enum comments above. 83 + // NOTE: If you set this to CENTER, see special instructions for the 84 + // tray_to_lens_distance field below. 85 + optional VerticalAlignmentType vertical_alignment = 11 [default = BOTTOM]; 86 + 87 + // If the phone is aligned vertically within the device by resting against 88 + // a fixed top or bottom tray, this is the distance from the tray to 89 + // optical center of the lenses. 90 + // This is a required field for distortion rendering, and must be positive. 91 + // NOTE: Due to a bug in initial versions of the SDK's, this field 92 + // must be set explicitly to .035 when vertical_alignment = CENTER. 93 + optional float tray_to_lens_distance = 6; 94 + 95 + // Coefficients Ki for pincushion distortion function which maps 96 + // from position on real screen to virtual screen (i.e. texture) relative 97 + // to optical center: 98 + // 99 + // p' = p (1 + K1 r^2 + K2 r^4 + ... + Kn r^(2n)) 100 + // 101 + // where r is the distance in tan-angle units from the optical center, 102 + // p the input point, and p' the output point. Tan-angle units can be 103 + // computed as distance on the screen divided by distance from the 104 + // virtual eye to the screen. 105 + repeated float distortion_coefficients = 7 [packed = true]; 106 + 107 + enum ButtonType { 108 + // No physical button, and touch screen is not easily accessible. 109 + NONE = 0; 110 + // HMD has integrated magnet switch similar to original Cardboard. 111 + MAGNET = 1; 112 + // At least a portion of touch screen is easily accessible to user for taps. 113 + TOUCH = 2; 114 + // Touch screen is triggered indirectly via integrated button on the HMD. 115 + INDIRECT_TOUCH = 3; 116 + } 117 + 118 + // Specify primary input mechanism of the HMD. Intended for advisory 119 + // purposes only, to address simple questions such as "can HMD 120 + // be used with apps requiring a physical button event?" or "what icon 121 + // should be used to represent button action to the user?". 122 + optional ButtonType primary_button = 12 [default = MAGNET]; 123 + }
+2 -1
src/xrt/drivers/CMakeLists.txt
··· 1 - # Copyright 2019-2021, Collabora, Ltd. 2 # 3 # SPDX-License-Identifier: BSL-1.0 4 ··· 395 aux_android 396 ${ANDROID_LIBRARY} 397 ) 398 list(APPEND ENABLED_DRIVERS android) 399 endif() 400
··· 1 + # Copyright 2019-2025, Collabora, Ltd. 2 # 3 # SPDX-License-Identifier: BSL-1.0 4 ··· 395 aux_android 396 ${ANDROID_LIBRARY} 397 ) 398 + target_link_libraries(drv_android PRIVATE xrt-external-cardboard) 399 list(APPEND ENABLED_DRIVERS android) 400 endif() 401
+129 -14
src/xrt/drivers/android/android_sensors.c
··· 1 // Copyright 2013, Fredrik Hultin. 2 // Copyright 2013, Jakob Bornecrantz. 3 // Copyright 2015, Joey Ferwerda. 4 - // Copyright 2020-2023, Collabora, Ltd. 5 // SPDX-License-Identifier: BSL-1.0 6 /*! 7 * @file 8 * @brief Android sensors driver code. 9 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 10 * @ingroup drv_android 11 */ 12 ··· 18 #include "util/u_var.h" 19 #include "util/u_visibility_mask.h" 20 21 #include "android/android_globals.h" 22 #include "android/android_custom_surface.h" 23 24 #include <xrt/xrt_config_android.h> ··· 40 return (struct android_device *)xdev; 41 } 42 43 // Callback for the Android sensor event queue 44 static int 45 android_sensor_callback(ASensorEvent *event, struct android_device *d) ··· 251 d->base.name = XRT_DEVICE_GENERIC_HMD; 252 d->base.destroy = android_device_destroy; 253 d->base.update_inputs = u_device_noop_update_inputs; 254 d->base.get_tracked_pose = android_device_get_tracked_pose; 255 d->base.get_view_poses = u_device_get_view_poses; 256 d->base.get_visibility_mask = u_device_get_visibility_mask; ··· 284 285 d->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / metrics.refresh_rate); 286 287 - // Everything done, finally start the thread. 288 - os_thread_helper_init(&d->oth); 289 - ret = os_thread_helper_start(&d->oth, android_run_thread, d); 290 - if (ret != 0) { 291 - ANDROID_ERROR(d, "Failed to start thread!"); 292 - android_device_destroy(&d->base); 293 - return NULL; 294 - } 295 - 296 const uint32_t w_pixels = metrics.width_pixels; 297 const uint32_t h_pixels = metrics.height_pixels; 298 ··· 300 const float w_meters = ((float)w_pixels / (float)metrics.xdpi) * 0.0254f; 301 const float h_meters = ((float)h_pixels / (float)metrics.ydpi) * 0.0254f; 302 303 - struct u_cardboard_distortion_arguments args = { 304 .distortion_k = {0.441f, 0.156f, 0.f, 0.f, 0.f}, 305 .screen = 306 { ··· 320 .angle_down = -angle, 321 }, 322 }; 323 324 u_distortion_cardboard_calculate(&args, d->base.hmd, &d->cardboard); 325 326 327 u_var_add_root(d, "Android phone", true); 328 u_var_add_ro_vec3_f32(d, &d->fusion.last.accel, "last.accel"); 329 u_var_add_ro_vec3_f32(d, &d->fusion.last.gyro, "last.gyro"); 330 331 d->base.supported.orientation_tracking = true; 332 d->base.supported.position_tracking = false; 333 - 334 - // Distortion information. 335 - u_distortion_mesh_fill_in_compute(&d->base); 336 337 ANDROID_DEBUG(d, "Created device!"); 338
··· 1 // Copyright 2013, Fredrik Hultin. 2 // Copyright 2013, Jakob Bornecrantz. 3 // Copyright 2015, Joey Ferwerda. 4 + // Copyright 2020-2025, Collabora, Ltd. 5 // SPDX-License-Identifier: BSL-1.0 6 /*! 7 * @file 8 * @brief Android sensors driver code. 9 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 10 + * @author Korcan Hussein <korcan.hussein@collabora.com> 11 + * @author Simon Zeni <simon.zeni@collabora.com> 12 * @ingroup drv_android 13 */ 14 ··· 20 #include "util/u_var.h" 21 #include "util/u_visibility_mask.h" 22 23 + #include "cardboard_device.pb.h" 24 + #include "pb_decode.h" 25 + 26 #include "android/android_globals.h" 27 + #include "android/android_content.h" 28 #include "android/android_custom_surface.h" 29 30 #include <xrt/xrt_config_android.h> ··· 46 return (struct android_device *)xdev; 47 } 48 49 + static bool 50 + read_file(pb_istream_t *stream, uint8_t *buf, size_t count) 51 + { 52 + U_LOG_E("read_file callback"); 53 + FILE *file = (FILE *)stream->state; 54 + if (buf == NULL) { 55 + while (count-- && fgetc(file) != EOF) 56 + ; 57 + return count == 0; 58 + } 59 + 60 + bool status = (fread(buf, 1, count, file) == count); 61 + 62 + if (feof(file)) { 63 + stream->bytes_left = 0; 64 + } 65 + 66 + return status; 67 + } 68 + 69 + static bool 70 + read_buffer(pb_istream_t *stream, const pb_field_t *field, void **arg) 71 + { 72 + U_LOG_E("read_file callback"); 73 + uint8_t *buffer = (uint8_t *)*arg; 74 + return pb_read(stream, buffer, stream->bytes_left); 75 + } 76 + 77 + static bool 78 + load_cardboard_distortion(struct android_device *d, 79 + struct xrt_android_display_metrics *metrics, 80 + struct u_cardboard_distortion_arguments *args) 81 + { 82 + char external_storage_dir[PATH_MAX] = {0}; 83 + if (!android_content_get_files_dir(android_globals_get_context(), external_storage_dir, 84 + sizeof(external_storage_dir))) { 85 + ANDROID_ERROR(d, "failed to access files dir"); 86 + return false; 87 + } 88 + 89 + /* TODO: put file in Cardboard folder */ 90 + char device_params_file[PATH_MAX] = {0}; 91 + snprintf(device_params_file, sizeof(device_params_file), "%s/current_device_params", external_storage_dir); 92 + 93 + FILE *file = fopen(device_params_file, "rb"); 94 + if (file == NULL) { 95 + ANDROID_ERROR(d, "failed to open calibration file '%s'", device_params_file); 96 + return false; 97 + } 98 + 99 + pb_istream_t stream = {&read_file, file, SIZE_MAX, NULL}; 100 + cardboard_DeviceParams params = cardboard_DeviceParams_init_zero; 101 + 102 + char vendor[64] = {0}; 103 + params.vendor.arg = vendor; 104 + params.vendor.funcs.decode = read_buffer; 105 + 106 + char model[64] = {0}; 107 + params.model.arg = model; 108 + params.model.funcs.decode = read_buffer; 109 + 110 + float angles[4] = {0}; 111 + params.left_eye_field_of_view_angles.arg = angles; 112 + params.left_eye_field_of_view_angles.funcs.decode = read_buffer; 113 + 114 + params.distortion_coefficients.arg = args->distortion_k; 115 + params.distortion_coefficients.funcs.decode = read_buffer; 116 + 117 + if (!pb_decode(&stream, cardboard_DeviceParams_fields, &params)) { 118 + ANDROID_ERROR(d, "failed to read calibration file: %s", PB_GET_ERROR(&stream)); 119 + return false; 120 + } 121 + 122 + if (params.has_vertical_alignment) { 123 + if (params.vertical_alignment != cardboard_DeviceParams_VerticalAlignmentType_BOTTOM) { 124 + ANDROID_ERROR(d, "Only vertical alignment bottom supported"); 125 + return false; 126 + } 127 + } 128 + 129 + if (params.has_inter_lens_distance) { 130 + args->inter_lens_distance_meters = params.inter_lens_distance; 131 + } 132 + if (params.has_screen_to_lens_distance) { 133 + args->screen_to_lens_distance_meters = params.screen_to_lens_distance; 134 + } 135 + if (params.has_tray_to_lens_distance) { 136 + args->tray_to_lens_distance_meters = params.tray_to_lens_distance; 137 + } 138 + 139 + #define DEG_TO_RAD(x) (float)(x * M_PI / 180.0) 140 + args->fov = (struct xrt_fov){.angle_left = -DEG_TO_RAD(angles[0]), 141 + .angle_right = DEG_TO_RAD(angles[1]), 142 + .angle_down = -DEG_TO_RAD(angles[2]), 143 + .angle_up = DEG_TO_RAD(angles[3])}; 144 + #undef DEG_TO_RAD 145 + 146 + ANDROID_INFO(d, "loaded calibration for device %s (%s)", model, vendor); 147 + 148 + return true; 149 + } 150 + 151 // Callback for the Android sensor event queue 152 static int 153 android_sensor_callback(ASensorEvent *event, struct android_device *d) ··· 359 d->base.name = XRT_DEVICE_GENERIC_HMD; 360 d->base.destroy = android_device_destroy; 361 d->base.update_inputs = u_device_noop_update_inputs; 362 + d->base.set_output = u_device_ni_set_output; 363 d->base.get_tracked_pose = android_device_get_tracked_pose; 364 d->base.get_view_poses = u_device_get_view_poses; 365 d->base.get_visibility_mask = u_device_get_visibility_mask; ··· 393 394 d->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / metrics.refresh_rate); 395 396 const uint32_t w_pixels = metrics.width_pixels; 397 const uint32_t h_pixels = metrics.height_pixels; 398 ··· 400 const float w_meters = ((float)w_pixels / (float)metrics.xdpi) * 0.0254f; 401 const float h_meters = ((float)h_pixels / (float)metrics.ydpi) * 0.0254f; 402 403 + const struct u_cardboard_distortion_arguments cardboard_v1_distortion_args = { 404 .distortion_k = {0.441f, 0.156f, 0.f, 0.f, 0.f}, 405 .screen = 406 { ··· 420 .angle_down = -angle, 421 }, 422 }; 423 + struct u_cardboard_distortion_arguments args = cardboard_v1_distortion_args; 424 + if (!load_cardboard_distortion(d, &metrics, &args)) { 425 + ANDROID_WARN( 426 + d, "Failed to load cardboard calibration file, falling back to Cardboard V1 distortion values"); 427 + args = cardboard_v1_distortion_args; 428 + } 429 430 u_distortion_cardboard_calculate(&args, d->base.hmd, &d->cardboard); 431 432 + // Distortion information. 433 + u_distortion_mesh_fill_in_compute(&d->base); 434 + 435 + // Everything done, finally start the thread. 436 + os_thread_helper_init(&d->oth); 437 + ret = os_thread_helper_start(&d->oth, android_run_thread, d); 438 + if (ret != 0) { 439 + ANDROID_ERROR(d, "Failed to start thread!"); 440 + android_device_destroy(&d->base); 441 + return NULL; 442 + } 443 444 u_var_add_root(d, "Android phone", true); 445 + u_var_add_log_level(d, &d->log_level, "log_level"); 446 u_var_add_ro_vec3_f32(d, &d->fusion.last.accel, "last.accel"); 447 u_var_add_ro_vec3_f32(d, &d->fusion.last.gyro, "last.gyro"); 448 449 d->base.supported.orientation_tracking = true; 450 d->base.supported.position_tracking = false; 451 452 ANDROID_DEBUG(d, "Created device!"); 453