The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

st/oxr: Implement FB_haptic_pcm

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2463>

+464 -76
+2
CMakeLists.txt
··· 361 361 option(XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC "Enable XR_HTC_facial_tracking" OFF) 362 362 option(XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL "Enable XR_MNDX_force_feedback_curl" ON) 363 363 option(XRT_FEATURE_OPENXR_HAND_TRACKING_EXT "Enable XR_EXT_hand_tracking" ON) 364 + option(XRT_FEATURE_OPENXR_HAPTIC_PCM "Enable XR_FB_haptic_pcm" OFF) 364 365 option(XRT_FEATURE_OPENXR_HEADLESS "Enable XR_MND_headless" ON) 365 366 option(XRT_FEATURE_OPENXR_OVERLAY "Enable XR_EXTX_overlay" ON) 366 367 option(XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS "Enable XR_EXT_performance_settings" OFF) ··· 600 601 message(STATUS "# FEATURE_OPENXR_FACIAL_TRACKING_HTC: ${XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC}") 601 602 message(STATUS "# FEATURE_OPENXR_FORCE_FEEDBACK_CURL: ${XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL}") 602 603 message(STATUS "# FEATURE_OPENXR_HAND_TRACKING_EXT: ${XRT_FEATURE_OPENXR_HAND_TRACKING_EXT}") 604 + message(STATUS "# FEATURE_OPENXR_HAPTIC_PCM: ${XRT_FEATURE_OPENXR_HAPTIC_PCM}") 603 605 message(STATUS "# FEATURE_OPENXR_HEADLESS: ${XRT_FEATURE_OPENXR_HEADLESS}") 604 606 message(STATUS "# FEATURE_OPENXR_INTERACTION_EXT_EYE_GAZE: ${XRT_FEATURE_OPENXR_INTERACTION_EXT_EYE_GAZE}") 605 607 message(STATUS "# FEATURE_OPENXR_INTERACTION_EXT_HAND: ${XRT_FEATURE_OPENXR_INTERACTION_EXT_HAND}")
+1
scripts/generate_oxr_ext_support.py
··· 76 76 ['XR_FB_composition_layer_depth_test', 'XRT_FEATURE_OPENXR_LAYER_FB_DEPTH_TEST'], 77 77 ['XR_FB_face_tracking2', 'XRT_FEATURE_OPENXR_FACE_TRACKING2_FB'], 78 78 ['XR_FB_display_refresh_rate', 'XRT_FEATURE_OPENXR_DISPLAY_REFRESH_RATE'], 79 + ['XR_FB_haptic_pcm', 'XRT_FEATURE_OPENXR_HAPTIC_PCM'], 79 80 ['XR_FB_passthrough', 'XRT_FEATURE_OPENXR_LAYER_FB_PASSTHROUGH'], 80 81 ['XR_FB_touch_controller_pro', 'XRT_FEATURE_OPENXR_INTERACTION_TOUCH_PRO'], 81 82 ['XR_FB_touch_controller_proximity', 'XRT_FEATURE_OPENXR_INTERACTION_FB_PROXIMITY'],
+1 -1
src/xrt/auxiliary/util/u_device.c
··· 515 515 } 516 516 517 517 void 518 - u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 518 + u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 519 519 { 520 520 E(get_hand_tracking); 521 521 }
+1 -1
src/xrt/auxiliary/util/u_device.h
··· 226 226 * @ingroup aux_util 227 227 */ 228 228 void 229 - u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value); 229 + u_device_ni_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value); 230 230 231 231 /*! 232 232 * Not implemented function for @ref xrt_device::get_view_poses.
+12 -8
src/xrt/auxiliary/util/u_resampler.c
··· 70 70 } 71 71 72 72 // push without resampling 73 - size_t 74 - u_resampler_write_raw(struct u_resampler *resampler, const sample_t *samples, size_t num_samples) 73 + static size_t 74 + resampler_write_raw(struct u_resampler *resampler, const sample_t *samples, size_t num_samples) 75 75 { 76 76 // the amount of bytes we can write until we start overwriting the play index 77 77 size_t can_write = BETWEEN(resampler, resampler->write_index, resampler->read_index) - 1; 78 78 79 - if (can_write == 0) 79 + if (can_write == 0) { 80 80 return 0; 81 + } 81 82 82 83 size_t written = 0; 83 84 ··· 119 120 u_resampler_write(struct u_resampler *resampler, const sample_t *source_samples, size_t num_samples, float sample_rate) 120 121 { 121 122 // no writing needed 122 - if (num_samples == 0) 123 + if (num_samples == 0) { 123 124 return 0; 125 + } 124 126 125 127 // short-circuit if the sample rate is already matching, no resampling needed 126 128 if (sample_rate == resampler->sample_rate) { 127 - return u_resampler_write_raw(resampler, source_samples, num_samples); 129 + return resampler_write_raw(resampler, source_samples, num_samples); 128 130 } 129 131 130 132 const float target_sample_rate = resampler->sample_rate; ··· 139 141 size_t source_idx = TO_RATE(target_idx, target_sample_rate, sample_rate); 140 142 141 143 // can't read any more samples 142 - if (source_idx >= num_samples) 144 + if (source_idx >= num_samples) { 143 145 break; 146 + } 144 147 145 148 // can't write any more samples 146 - if (can_write == 0) 149 + if (can_write == 0) { 147 150 break; 151 + } 148 152 149 153 target_samples[target_idx] = source_samples[source_idx]; 150 154 ··· 153 157 } 154 158 155 159 // note: ignoring return value since we should never resample more than we can write 156 - u_resampler_write_raw(resampler, target_samples, target_idx); 160 + resampler_write_raw(resampler, target_samples, target_idx); 157 161 158 162 return TO_RATE(target_idx - 1, target_sample_rate, sample_rate); 159 163 }
+1 -1
src/xrt/drivers/ht_ctrl_emu/ht_ctrl_emu.cpp
··· 372 372 } 373 373 374 374 static void 375 - cemu_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 375 + cemu_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 376 376 { 377 377 // No-op, needed to avoid crash. 378 378 }
+1 -1
src/xrt/drivers/multi_wrapper/multi.c
··· 181 181 } 182 182 183 183 static void 184 - set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 184 + set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 185 185 { 186 186 struct multi_device *d = (struct multi_device *)xdev; 187 187 struct xrt_device *target = d->tracking_override.target;
+1 -1
src/xrt/drivers/ohmd/oh_device.c
··· 327 327 } 328 328 329 329 static void 330 - oh_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 330 + oh_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 331 331 { 332 332 struct oh_device *ohd = oh_device(xdev); 333 333
+1 -1
src/xrt/drivers/opengloves/opengloves_device.c
··· 173 173 } 174 174 175 175 static void 176 - opengloves_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 176 + opengloves_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 177 177 { 178 178 struct opengloves_device *od = opengloves_device(xdev); 179 179
+1 -1
src/xrt/drivers/psmv/psmv_driver.c
··· 922 922 } 923 923 924 924 static void 925 - psmv_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 925 + psmv_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 926 926 { 927 927 struct psmv_device *psmv = psmv_device(xdev); 928 928
+1 -1
src/xrt/drivers/pssense/pssense_driver.c
··· 677 677 } 678 678 679 679 static void 680 - pssense_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 680 + pssense_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 681 681 { 682 682 struct pssense_device *pssense = (struct pssense_device *)xdev; 683 683
+1 -1
src/xrt/drivers/qwerty/qwerty_device.c
··· 178 178 } 179 179 180 180 static void 181 - qwerty_set_output(struct xrt_device *xd, enum xrt_output_name name, const union xrt_output_value *value) 181 + qwerty_set_output(struct xrt_device *xd, enum xrt_output_name name, const struct xrt_output_value *value) 182 182 { 183 183 struct qwerty_device *qd = qwerty_device(xd); 184 184 float frequency = value->vibration.frequency;
+1 -1
src/xrt/drivers/remote/r_device.c
··· 190 190 } 191 191 192 192 static void 193 - r_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 193 + r_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 194 194 { 195 195 struct r_device *rd = r_device(xdev); 196 196 (void)rd;
+1 -1
src/xrt/drivers/remote/r_hmd.c
··· 124 124 } 125 125 126 126 static void 127 - r_hmd_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 127 + r_hmd_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 128 128 { 129 129 // Empty 130 130 }
+1 -1
src/xrt/drivers/rift_s/rift_s_controller.c
··· 510 510 } 511 511 512 512 static void 513 - rift_s_controller_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 513 + rift_s_controller_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 514 514 { 515 515 /* TODO: Implement haptic sending */ 516 516 }
+1 -1
src/xrt/drivers/simulated/simulated_controller.c
··· 189 189 } 190 190 191 191 static void 192 - simulated_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 192 + simulated_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 193 193 { 194 194 struct simulated_device *sd = simulated_device(xdev); 195 195 (void)sd;
+2 -2
src/xrt/drivers/survive/survive_driver.c
··· 377 377 } 378 378 379 379 static int 380 - survive_controller_haptic_pulse(struct survive_device *survive, const union xrt_output_value *value) 380 + survive_controller_haptic_pulse(struct survive_device *survive, const struct xrt_output_value *value) 381 381 { 382 382 float duration_seconds; 383 383 if (value->vibration.duration_ns == XRT_MIN_HAPTIC_DURATION) { ··· 407 407 static void 408 408 survive_controller_device_set_output(struct xrt_device *xdev, 409 409 enum xrt_output_name name, 410 - const union xrt_output_value *value) 410 + const struct xrt_output_value *value) 411 411 { 412 412 struct survive_device *survive = (struct survive_device *)xdev; 413 413
+2 -2
src/xrt/drivers/vive/vive_controller.c
··· 431 431 } 432 432 433 433 static int 434 - vive_controller_haptic_pulse(struct vive_controller_device *d, const union xrt_output_value *value) 434 + vive_controller_haptic_pulse(struct vive_controller_device *d, const struct xrt_output_value *value) 435 435 { 436 436 float duration_seconds; 437 437 if (value->vibration.duration_ns == XRT_MIN_HAPTIC_DURATION) { ··· 489 489 static void 490 490 vive_controller_device_set_output(struct xrt_device *xdev, 491 491 enum xrt_output_name name, 492 - const union xrt_output_value *value) 492 + const struct xrt_output_value *value) 493 493 { 494 494 struct vive_controller_device *d = vive_controller_device(xdev); 495 495
+1 -1
src/xrt/drivers/wmr/wmr_controller_hp.c
··· 307 307 } 308 308 309 309 static void 310 - wmr_controller_hp_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 310 + wmr_controller_hp_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 311 311 { 312 312 DRV_TRACE_MARKER(); 313 313
+1 -1
src/xrt/drivers/wmr/wmr_controller_og.c
··· 320 320 } 321 321 322 322 static void 323 - wmr_controller_og_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 323 + wmr_controller_og_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 324 324 { 325 325 DRV_TRACE_MARKER(); 326 326
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
··· 39 39 #cmakedefine XRT_FEATURE_OPENXR_FACIAL_TRACKING_HTC 40 40 #cmakedefine XRT_FEATURE_OPENXR_FORCE_FEEDBACK_CURL 41 41 #cmakedefine XRT_FEATURE_OPENXR_HAND_TRACKING_EXT 42 + #cmakedefine XRT_FEATURE_OPENXR_HAPTIC_PCM 42 43 #cmakedefine XRT_FEATURE_OPENXR_HEADLESS 43 44 #cmakedefine XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE 44 45 #cmakedefine XRT_FEATURE_OPENXR_INTERACTION_EXT_EYE_GAZE
+33 -12
src/xrt/include/xrt/xrt_defines.h
··· 1885 1885 enum xrt_force_feedback_location location; 1886 1886 }; 1887 1887 1888 + enum xrt_output_value_type 1889 + { 1890 + XRT_OUTPUT_VALUE_TYPE_VIBRATION, 1891 + XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION, 1892 + XRT_OUTPUT_VALUE_TYPE_FORCE_FEEDBACK, 1893 + }; 1894 + 1888 1895 /*! 1889 1896 * A union of all output types. 1890 1897 * 1891 1898 * @see xrt_output_type 1892 1899 * @ingroup xrt_iface math 1893 1900 */ 1894 - union xrt_output_value { 1895 - struct 1896 - { 1897 - float frequency; 1898 - float amplitude; 1899 - int64_t duration_ns; 1900 - } vibration; 1901 + struct xrt_output_value 1902 + { 1903 + enum xrt_output_value_type type; 1904 + 1905 + union { 1906 + struct 1907 + { 1908 + float frequency; 1909 + float amplitude; 1910 + int64_t duration_ns; 1911 + } vibration; 1912 + 1913 + struct 1914 + { 1915 + uint32_t buffer_size; 1916 + const float *buffer; 1917 + float sample_rate; 1918 + bool append; 1919 + uint32_t *samples_consumed; 1920 + } pcm_vibration; 1901 1921 1902 - struct 1903 - { 1904 - struct xrt_output_force_feedback force_feedback[5]; 1905 - uint64_t force_feedback_location_count; 1906 - } force_feedback; 1922 + struct 1923 + { 1924 + struct xrt_output_force_feedback force_feedback[5]; 1925 + uint64_t force_feedback_location_count; 1926 + } force_feedback; 1927 + }; 1907 1928 }; 1908 1929 1909 1930
+29 -2
src/xrt/include/xrt/xrt_device.h
··· 235 235 }; 236 236 237 237 /*! 238 + * Output limits of a particular device 239 + */ 240 + struct xrt_output_limits 241 + { 242 + //! The sample rate of the device's haptic PCM support, 0 if haptic PCM is not supported. 243 + float haptic_pcm_sample_rate; 244 + }; 245 + 246 + /*! 238 247 * @interface xrt_device 239 248 * 240 249 * A single HMD or input device. ··· 415 424 * @param[in] value The value to set the output to. 416 425 * @see xrt_output_name 417 426 */ 418 - void (*set_output)(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value); 427 + void (*set_output)(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value); 428 + 429 + /*! 430 + * Gets limits of this devices outputs. 431 + * 432 + * @param[in] xdev The device. 433 + * @param[out] limits The returned limits. 434 + */ 435 + xrt_result_t (*get_output_limits)(struct xrt_device *xdev, struct xrt_output_limits *limits); 419 436 420 437 /*! 421 438 * Begin a plane detection request ··· 708 725 * @public @memberof xrt_device 709 726 */ 710 727 static inline void 711 - xrt_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 728 + xrt_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 712 729 { 713 730 xdev->set_output(xdev, name, value); 731 + } 732 + 733 + static inline xrt_result_t 734 + xrt_device_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits) 735 + { 736 + if (xdev->get_output_limits) { 737 + return xdev->get_output_limits(xdev, limits); 738 + } else { 739 + return XRT_ERROR_NOT_IMPLEMENTED; 740 + } 714 741 } 715 742 716 743 /*!
+53 -3
src/xrt/ipc/client/ipc_client_device.c
··· 20 20 #include "util/u_device.h" 21 21 22 22 #include "client/ipc_client.h" 23 + #include "client/ipc_client_connection.h" 23 24 #include "ipc_client_generated.h" 24 25 25 26 #include <math.h> ··· 181 182 } 182 183 183 184 static void 184 - ipc_client_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 185 + ipc_client_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 186 + { 187 + ipc_client_device_t *icd = ipc_client_device(xdev); 188 + struct ipc_connection *ipc_c = icd->ipc_c; 189 + 190 + xrt_result_t xret; 191 + if (value->type == XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION) { 192 + uint32_t samples_sent = MIN(value->pcm_vibration.sample_rate, 4000); 193 + 194 + struct ipc_pcm_haptic_buffer samples = { 195 + .append = value->pcm_vibration.append, 196 + .num_samples = samples_sent, 197 + .sample_rate = value->pcm_vibration.sample_rate, 198 + }; 199 + 200 + ipc_client_connection_lock(ipc_c); 201 + 202 + xret = ipc_send_device_set_haptic_output_locked(ipc_c, icd->device_id, name, &samples); 203 + IPC_CHK_WITH_RET(ipc_c, xret, "ipc_send_device_set_haptic_output_locked", ); 204 + 205 + xrt_result_t alloc_xret; 206 + xret = ipc_receive(&ipc_c->imc, &alloc_xret, sizeof alloc_xret); 207 + if (xret != XRT_SUCCESS || alloc_xret != XRT_SUCCESS) { 208 + goto send_haptic_output_end; 209 + } 210 + 211 + xret = ipc_send(&ipc_c->imc, value->pcm_vibration.buffer, sizeof(float) * samples_sent); 212 + if (xret != XRT_SUCCESS) { 213 + goto send_haptic_output_end; 214 + } 215 + 216 + xret = ipc_receive(&ipc_c->imc, value->pcm_vibration.samples_consumed, 217 + sizeof(*value->pcm_vibration.samples_consumed)); 218 + if (xret != XRT_SUCCESS) { 219 + goto send_haptic_output_end; 220 + } 221 + 222 + send_haptic_output_end: 223 + ipc_client_connection_unlock(ipc_c); 224 + } else { 225 + xret = ipc_call_device_set_output(ipc_c, icd->device_id, name, value); 226 + IPC_CHK_ONLY_PRINT(ipc_c, xret, "ipc_call_device_set_output"); 227 + } 228 + } 229 + 230 + xrt_result_t 231 + ipc_client_device_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits) 185 232 { 186 233 ipc_client_device_t *icd = ipc_client_device(xdev); 187 234 188 - xrt_result_t xret = ipc_call_device_set_output(icd->ipc_c, icd->device_id, name, value); 189 - IPC_CHK_ONLY_PRINT(icd->ipc_c, xret, "ipc_call_device_set_output"); 235 + xrt_result_t xret = ipc_call_device_get_output_limits(icd->ipc_c, icd->device_id, limits); 236 + IPC_CHK_ONLY_PRINT(icd->ipc_c, xret, "ipc_call_device_get_output_limits"); 237 + 238 + return xret; 190 239 } 191 240 192 241 static xrt_result_t ··· 221 270 icd->base.get_body_joints = ipc_client_device_get_body_joints; 222 271 icd->base.get_view_poses = ipc_client_device_get_view_poses; 223 272 icd->base.set_output = ipc_client_device_set_output; 273 + icd->base.get_output_limits = ipc_client_device_get_output_limits; 224 274 icd->base.get_visibility_mask = ipc_client_device_get_visibility_mask; 225 275 icd->base.destroy = ipc_client_device_destroy; 226 276
+86 -1
src/xrt/ipc/server/ipc_server_handler.c
··· 2254 2254 ipc_handle_device_set_output(volatile struct ipc_client_state *ics, 2255 2255 uint32_t id, 2256 2256 enum xrt_output_name name, 2257 - const union xrt_output_value *value) 2257 + const struct xrt_output_value *value) 2258 2258 { 2259 2259 // To make the code a bit more readable. 2260 2260 uint32_t device_id = id; ··· 2264 2264 xrt_device_set_output(xdev, name, value); 2265 2265 2266 2266 return XRT_SUCCESS; 2267 + } 2268 + 2269 + xrt_result_t 2270 + ipc_handle_device_set_haptic_output(volatile struct ipc_client_state *ics, 2271 + uint32_t id, 2272 + enum xrt_output_name name, 2273 + const struct ipc_pcm_haptic_buffer *buffer) 2274 + { 2275 + IPC_TRACE_MARKER(); 2276 + struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; 2277 + struct ipc_server *s = ics->server; 2278 + 2279 + xrt_result_t xret; 2280 + 2281 + // To make the code a bit more readable. 2282 + uint32_t device_id = id; 2283 + struct xrt_device *xdev = get_xdev(ics, device_id); 2284 + 2285 + os_mutex_lock(&ics->server->global_state.lock); 2286 + 2287 + float *samples = U_TYPED_ARRAY_CALLOC(float, buffer->num_samples); 2288 + 2289 + // send the allocation result 2290 + xret = samples ? XRT_SUCCESS : XRT_ERROR_ALLOCATION; 2291 + xret = ipc_send(imc, &xret, sizeof xret); 2292 + if (xret != XRT_SUCCESS) { 2293 + IPC_ERROR(ics->server, "Failed to send samples allocate result"); 2294 + goto set_haptic_output_end; 2295 + } 2296 + 2297 + if (!samples) { 2298 + IPC_ERROR(s, "Failed to allocate samples for haptic output"); 2299 + xret = XRT_ERROR_ALLOCATION; 2300 + goto set_haptic_output_end; 2301 + } 2302 + 2303 + xret = ipc_receive(imc, samples, sizeof(float) * buffer->num_samples); 2304 + if (xret != XRT_SUCCESS) { 2305 + IPC_ERROR(s, "Failed to receive samples"); 2306 + goto set_haptic_output_end; 2307 + } 2308 + 2309 + uint32_t samples_consumed; 2310 + struct xrt_output_value value = { 2311 + .type = XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION, 2312 + .pcm_vibration = 2313 + { 2314 + .append = buffer->append, 2315 + .buffer_size = buffer->num_samples, 2316 + .sample_rate = buffer->sample_rate, 2317 + .samples_consumed = &samples_consumed, 2318 + .buffer = samples, 2319 + }, 2320 + }; 2321 + 2322 + // Set the output. 2323 + xrt_device_set_output(xdev, name, &value); 2324 + 2325 + xret = ipc_send(imc, &samples_consumed, sizeof samples_consumed); 2326 + if (xret != XRT_SUCCESS) { 2327 + IPC_ERROR(ics->server, "Failed to send samples consumed"); 2328 + goto set_haptic_output_end; 2329 + } 2330 + 2331 + xret = XRT_SUCCESS; 2332 + 2333 + set_haptic_output_end: 2334 + os_mutex_unlock(&ics->server->global_state.lock); 2335 + 2336 + free(samples); 2337 + 2338 + return xret; 2339 + } 2340 + 2341 + xrt_result_t 2342 + ipc_handle_device_get_output_limits(volatile struct ipc_client_state *ics, 2343 + uint32_t id, 2344 + struct xrt_output_limits *limits) 2345 + { 2346 + // To make the code a bit more readable. 2347 + uint32_t device_id = id; 2348 + struct xrt_device *xdev = get_xdev(ics, device_id); 2349 + 2350 + // Set the output. 2351 + return xrt_device_get_output_limits(xdev, limits); 2267 2352 } 2268 2353 2269 2354 xrt_result_t
+7
src/xrt/ipc/shared/ipc_protocol.h
··· 373 373 374 374 static_assert(sizeof(struct ipc_info_get_view_poses_2) == 144, 375 375 "invalid structure size, maybe different 32/64 bits sizes or padding"); 376 + 377 + struct ipc_pcm_haptic_buffer 378 + { 379 + uint32_t num_samples; 380 + float sample_rate; 381 + bool append; 382 + };
+22 -1
src/xrt/ipc/shared/proto.json
··· 509 509 "in": [ 510 510 {"name": "id", "type": "uint32_t"}, 511 511 {"name": "name", "type": "enum xrt_output_name"}, 512 - {"name": "value", "type": "union xrt_output_value"} 512 + {"name": "value", "type": "struct xrt_output_value"} 513 + ] 514 + }, 515 + 516 + "device_set_haptic_output": { 517 + "varlen": true, 518 + "in": [ 519 + {"name": "id", "type": "uint32_t"}, 520 + {"name": "name", "type": "enum xrt_output_name"}, 521 + {"name": "samples", "type": "struct ipc_pcm_haptic_buffer"} 522 + ], 523 + "out":[ 524 + {"name": "samples_consumed", "type": "uint32_t"} 525 + ] 526 + }, 527 + 528 + "device_get_output_limits": { 529 + "in": [ 530 + {"name": "id", "type": "uint32_t"} 531 + ], 532 + "out":[ 533 + {"name": "limits", "type": "struct xrt_output_limits"} 513 534 ] 514 535 }, 515 536
+18 -1
src/xrt/state_trackers/oxr/oxr_api_action.c
··· 792 792 OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrApplyHapticFeedback"); 793 793 OXR_VERIFY_SESSION_NOT_LOST(&log, sess); 794 794 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, hapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO); 795 + OXR_VERIFY_ARG_NOT_NULL(&log, hapticEvent); 796 + OXR_VERIFY_ACTION_NOT_NULL(&log, hapticActionInfo->action, act); 797 + 798 + #ifdef OXR_HAVE_FB_haptic_pcm 799 + if (hapticEvent->type != XR_TYPE_HAPTIC_PCM_VIBRATION_FB && hapticEvent->type != XR_TYPE_HAPTIC_VIBRATION) { 800 + return oxr_error( 801 + &log, XR_ERROR_VALIDATION_FAILURE, 802 + "Haptic event type was not XR_TYPE_HAPTIC_VIBRATION or XR_TYPE_HAPTIC_PCM_VIBRATION_FB, got %d", 803 + hapticEvent->type); 804 + } 805 + 806 + if (hapticEvent->type == XR_TYPE_HAPTIC_PCM_VIBRATION_FB) { 807 + OXR_VERIFY_EXTENSION(&log, sess->sys->inst, FB_haptic_pcm); 808 + } else { 809 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, hapticEvent, XR_TYPE_HAPTIC_VIBRATION); 810 + } 811 + #else 795 812 OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, hapticEvent, XR_TYPE_HAPTIC_VIBRATION); 796 - OXR_VERIFY_ACTION_NOT_NULL(&log, hapticActionInfo->action, act); 813 + #endif 797 814 798 815 ret = oxr_verify_subaction_path_get(&log, act->act_set->inst, hapticActionInfo->subactionPath, 799 816 &act->data->subaction_paths, &subaction_paths, "getInfo->subactionPath");
+6
src/xrt/state_trackers/oxr/oxr_api_funcs.h
··· 571 571 XRAPI_ATTR XrResult XRAPI_CALL 572 572 oxr_xrRequestDisplayRefreshRateFB(XrSession session, float displayRefreshRate); 573 573 574 + //! OpenXR API function @ep{xrGetDeviceSampleRateFB} 575 + XRAPI_ATTR XrResult XRAPI_CALL 576 + oxr_xrGetDeviceSampleRateFB(XrSession session, 577 + const XrHapticActionInfo *hapticActionInfo, 578 + XrDevicePcmSampleRateGetInfoFB *deviceSampleRate); 579 + 574 580 //! OpenXR API function @ep{xrLocateSpacesKHR} 575 581 XRAPI_ATTR XrResult XRAPI_CALL 576 582 oxr_xrLocateSpacesKHR(XrSession session, const XrSpacesLocateInfoKHR *locateInfo, XrSpaceLocationsKHR *spaceLocations);
+4
src/xrt/state_trackers/oxr/oxr_api_negotiate.c
··· 260 260 ENTRY_IF_EXT(xrRequestDisplayRefreshRateFB, FB_display_refresh_rate); 261 261 #endif 262 262 263 + #ifdef OXR_HAVE_FB_haptic_pcm 264 + ENTRY_IF_EXT(xrGetDeviceSampleRateFB, FB_haptic_pcm); 265 + #endif 266 + 263 267 #ifdef OXR_HAVE_FB_passthrough 264 268 ENTRY_IF_EXT(xrCreateGeometryInstanceFB, FB_passthrough); 265 269 ENTRY_IF_EXT(xrCreatePassthroughFB, FB_passthrough);
+88
src/xrt/state_trackers/oxr/oxr_api_session.c
··· 671 671 672 672 /* 673 673 * 674 + * XR_FB_haptic_pcm 675 + * 676 + */ 677 + 678 + #ifdef OXR_HAVE_FB_haptic_pcm 679 + 680 + static bool 681 + get_action_output_pcm_sample_rate(struct oxr_session *sess, struct oxr_action_cache *cache, float *sample_rate) 682 + { 683 + for (uint32_t i = 0; i < cache->output_count; i++) { 684 + struct oxr_action_output *output = &cache->outputs[i]; 685 + struct xrt_device *xdev = output->xdev; 686 + 687 + struct xrt_output_limits output_limits; 688 + xrt_result_t result = xrt_device_get_output_limits(xdev, &output_limits); 689 + if (result != XRT_SUCCESS) { 690 + // default to something sane 691 + output_limits = (struct xrt_output_limits){0}; 692 + } 693 + 694 + (*sample_rate) = output_limits.haptic_pcm_sample_rate; 695 + if (output_limits.haptic_pcm_sample_rate > 0) { 696 + return true; 697 + } 698 + } 699 + 700 + return false; 701 + } 702 + 703 + XRAPI_ATTR XrResult XRAPI_CALL 704 + oxr_xrGetDeviceSampleRateFB(XrSession session, 705 + const XrHapticActionInfo *hapticActionInfo, 706 + XrDevicePcmSampleRateGetInfoFB *deviceSampleRate) 707 + { 708 + OXR_TRACE_MARKER(); 709 + 710 + struct oxr_session *sess = NULL; 711 + struct oxr_action *act = NULL; 712 + struct oxr_subaction_paths subaction_paths = {0}; 713 + struct oxr_logger log; 714 + XrResult ret; 715 + OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrGetDeviceSampleRateFB"); 716 + OXR_VERIFY_SESSION_NOT_LOST(&log, sess); 717 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, hapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO); 718 + OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, deviceSampleRate, XR_TYPE_DEVICE_PCM_SAMPLE_RATE_GET_INFO_FB); 719 + OXR_VERIFY_ACTION_NOT_NULL(&log, hapticActionInfo->action, act); 720 + OXR_VERIFY_EXTENSION(&log, sess->sys->inst, FB_haptic_pcm); 721 + 722 + // get the subaction paths 723 + ret = oxr_verify_subaction_path_get(&log, act->act_set->inst, hapticActionInfo->subactionPath, 724 + &act->data->subaction_paths, &subaction_paths, "getInfo->subactionPath"); 725 + if (ret != XR_SUCCESS) { 726 + return ret; 727 + } 728 + 729 + // make sure it's a vibration action 730 + if (act->data->action_type != XR_ACTION_TYPE_VIBRATION_OUTPUT) { 731 + return oxr_error(&log, XR_ERROR_ACTION_TYPE_MISMATCH, "Not created with output vibration type"); 732 + } 733 + 734 + // get the attached action 735 + struct oxr_action_attachment *act_attached = NULL; 736 + 737 + oxr_session_get_action_attachment(sess, act->act_key, &act_attached); 738 + if (act_attached == NULL) { 739 + return oxr_error(&log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "Action has not been attached to this session"); 740 + } 741 + 742 + // find any device with a valid sample rate, and return it 743 + #define GET_SAMPLE_RATE(X) \ 744 + if (subaction_paths.X || subaction_paths.any) { \ 745 + if (get_action_output_pcm_sample_rate(sess, &act_attached->X, &deviceSampleRate->sampleRate)) \ 746 + return oxr_session_success_focused_result(sess); \ 747 + } 748 + 749 + OXR_FOR_EACH_SUBACTION_PATH(GET_SAMPLE_RATE) 750 + #undef GET_SAMPLE_RATE 751 + 752 + // no devices found 753 + deviceSampleRate->sampleRate = 0; 754 + 755 + return XR_SUCCESS; 756 + } 757 + 758 + #endif 759 + 760 + /* 761 + * 674 762 * XR_KHR_android_thread_settings 675 763 * 676 764 */
+12
src/xrt/state_trackers/oxr/oxr_extension_support.h
··· 510 510 511 511 512 512 /* 513 + * XR_FB_haptic_pcm 514 + */ 515 + #if defined(XR_FB_haptic_pcm) && defined(XRT_FEATURE_OPENXR_HAPTIC_PCM) 516 + #define OXR_HAVE_FB_haptic_pcm 517 + #define OXR_EXTENSION_SUPPORT_FB_haptic_pcm(_) _(FB_haptic_pcm, FB_HAPTIC_PCM) 518 + #else 519 + #define OXR_EXTENSION_SUPPORT_FB_haptic_pcm(_) 520 + #endif 521 + 522 + 523 + /* 513 524 * XR_FB_passthrough 514 525 */ 515 526 #if defined(XR_FB_passthrough) && defined(XRT_FEATURE_OPENXR_LAYER_FB_PASSTHROUGH) ··· 825 836 OXR_EXTENSION_SUPPORT_FB_composition_layer_depth_test(_) \ 826 837 OXR_EXTENSION_SUPPORT_FB_face_tracking2(_) \ 827 838 OXR_EXTENSION_SUPPORT_FB_display_refresh_rate(_) \ 839 + OXR_EXTENSION_SUPPORT_FB_haptic_pcm(_) \ 828 840 OXR_EXTENSION_SUPPORT_FB_passthrough(_) \ 829 841 OXR_EXTENSION_SUPPORT_FB_touch_controller_pro(_) \ 830 842 OXR_EXTENSION_SUPPORT_FB_touch_controller_proximity(_) \
+57 -27
src/xrt/state_trackers/oxr/oxr_input.c
··· 45 45 struct oxr_action_set **act_set); 46 46 47 47 static void 48 - oxr_session_get_action_attachment(struct oxr_session *sess, 49 - uint32_t act_key, 50 - struct oxr_action_attachment **out_act_attached); 51 - 52 - static void 53 48 oxr_action_cache_update(struct oxr_logger *log, 54 49 struct oxr_session *sess, 55 50 uint32_t countActionSets, ··· 890 885 // Set this as stopped. 891 886 cache->stop_output_time = 0; 892 887 893 - union xrt_output_value value = {0}; 888 + struct xrt_output_value value = {.type = XRT_OUTPUT_VALUE_TYPE_VIBRATION, .vibration = {0}}; 894 889 895 890 for (uint32_t i = 0; i < cache->output_count; i++) { 896 891 struct oxr_action_output *output = &cache->outputs[i]; ··· 1679 1674 } 1680 1675 } 1681 1676 1682 - /*! 1683 - * Given an action act_key, look up the @ref oxr_action_attachment of 1684 - * the associated action in the given Session. 1685 - * 1686 - * @private @memberof oxr_session 1687 - */ 1688 - static void 1677 + void 1689 1678 oxr_session_get_action_attachment(struct oxr_session *sess, 1690 1679 uint32_t act_key, 1691 1680 struct oxr_action_attachment **out_act_attached) ··· 2163 2152 { 2164 2153 cache->stop_output_time = stop; 2165 2154 2166 - union xrt_output_value value = {0}; 2155 + struct xrt_output_value value = {0}; 2167 2156 value.vibration.frequency = data->frequency; 2168 2157 value.vibration.amplitude = data->amplitude; 2169 2158 value.vibration.duration_ns = data->duration; 2159 + value.type = XRT_OUTPUT_VALUE_TYPE_VIBRATION; 2160 + 2161 + for (uint32_t i = 0; i < cache->output_count; i++) { 2162 + struct oxr_action_output *output = &cache->outputs[i]; 2163 + struct xrt_device *xdev = output->xdev; 2164 + 2165 + xrt_device_set_output(xdev, output->name, &value); 2166 + } 2167 + } 2168 + 2169 + XRT_MAYBE_UNUSED static void 2170 + set_action_output_vibration_pcm(struct oxr_session *sess, 2171 + struct oxr_action_cache *cache, 2172 + const XrHapticPcmVibrationFB *data) 2173 + { 2174 + struct xrt_output_value value = {0}; 2175 + value.pcm_vibration.append = data->append; 2176 + value.pcm_vibration.buffer = data->buffer; 2177 + value.pcm_vibration.buffer_size = data->bufferSize; 2178 + value.pcm_vibration.sample_rate = data->sampleRate; 2179 + value.pcm_vibration.samples_consumed = data->samplesConsumed; 2180 + value.type = XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION; 2170 2181 2171 2182 for (uint32_t i = 0; i < cache->output_count; i++) { 2172 2183 struct oxr_action_output *output = &cache->outputs[i]; ··· 2190 2201 return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "Action has not been attached to this session"); 2191 2202 } 2192 2203 2193 - const XrHapticVibration *data = (const XrHapticVibration *)hapticEvent; 2194 - 2195 - // This should all be moved into the drivers. 2196 - const int64_t min_pulse_time_ns = time_s_to_ns(0.1); 2197 - int64_t now_ns = time_state_get_now(sess->sys->inst->timekeeping); 2198 - int64_t stop_ns = 0; 2199 - if (data->duration <= 0) { 2200 - stop_ns = now_ns + min_pulse_time_ns; 2201 - } else { 2202 - stop_ns = now_ns + data->duration; 2204 + if (sess->state != XR_SESSION_STATE_FOCUSED) { 2205 + return oxr_session_success_focused_result(sess); 2203 2206 } 2204 2207 2205 - bool is_focused = sess->state == XR_SESSION_STATE_FOCUSED; 2208 + if (hapticEvent->type == XR_TYPE_HAPTIC_VIBRATION) { 2209 + const XrHapticVibration *data = (const XrHapticVibration *)hapticEvent; 2210 + 2211 + // This should all be moved into the drivers. 2212 + const int64_t min_pulse_time_ns = time_s_to_ns(0.1); 2213 + int64_t now_ns = time_state_get_now(sess->sys->inst->timekeeping); 2214 + int64_t stop_ns = 0; 2215 + if (data->duration <= 0) { 2216 + stop_ns = now_ns + min_pulse_time_ns; 2217 + } else { 2218 + stop_ns = now_ns + data->duration; 2219 + } 2206 2220 2207 2221 #define SET_OUT_VIBRATION(X) \ 2208 - if (is_focused && act_attached->X.current.active && (subaction_paths.X || subaction_paths.any)) { \ 2222 + if (act_attached->X.current.active && (subaction_paths.X || subaction_paths.any)) { \ 2209 2223 set_action_output_vibration(sess, &act_attached->X, stop_ns, data); \ 2210 2224 } 2211 2225 2212 - OXR_FOR_EACH_SUBACTION_PATH(SET_OUT_VIBRATION) 2226 + OXR_FOR_EACH_SUBACTION_PATH(SET_OUT_VIBRATION) 2227 + #undef SET_OUT_VIBRATION 2228 + #ifdef OXR_HAVE_FB_haptic_pcm 2229 + } else if (hapticEvent->type == XR_TYPE_HAPTIC_PCM_VIBRATION_FB) { 2230 + const XrHapticPcmVibrationFB *data = (const XrHapticPcmVibrationFB *)hapticEvent; 2231 + 2232 + #define SET_OUT_VIBRATION(X) \ 2233 + if (act_attached->X.current.active && (subaction_paths.X || subaction_paths.any)) { \ 2234 + set_action_output_vibration_pcm(sess, &act_attached->X, data); \ 2235 + } 2236 + 2237 + OXR_FOR_EACH_SUBACTION_PATH(SET_OUT_VIBRATION) 2213 2238 #undef SET_OUT_VIBRATION 2239 + #endif /* OXR_HAVE_FB_haptic_pcm */ 2240 + } else { 2241 + return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "Received haptic feedback of invalid type"); 2242 + } 2243 + 2214 2244 return oxr_session_success_focused_result(sess); 2215 2245 } 2216 2246
+11
src/xrt/state_trackers/oxr/oxr_objects.h
··· 514 514 oxr_session_update_action_bindings(struct oxr_logger *log, struct oxr_session *sess); 515 515 516 516 /*! 517 + * Given an action act_key, look up the @ref oxr_action_attachment of 518 + * the associated action in the given Session. 519 + * 520 + * @private @memberof oxr_session 521 + */ 522 + void 523 + oxr_session_get_action_attachment(struct oxr_session *sess, 524 + uint32_t act_key, 525 + struct oxr_action_attachment **out_act_attached); 526 + 527 + /*! 517 528 * @public @memberof oxr_session 518 529 */ 519 530 XrResult
+2 -1
src/xrt/state_trackers/oxr/oxr_session.c
··· 1440 1440 { 1441 1441 struct xrt_device *xdev = hand_tracker->xdev; 1442 1442 1443 - union xrt_output_value result; 1443 + struct xrt_output_value result = {0}; 1444 + result.type = XRT_OUTPUT_VALUE_TYPE_FORCE_FEEDBACK; 1444 1445 result.force_feedback.force_feedback_location_count = locations->locationCount; 1445 1446 for (uint32_t i = 0; i < locations->locationCount; i++) { 1446 1447 result.force_feedback.force_feedback[i].location =
+1 -1
src/xrt/state_trackers/steamvr_drv/ovrd_driver.cpp
··· 1578 1578 return; 1579 1579 } 1580 1580 1581 - union xrt_output_value out; 1581 + struct xrt_output_value out; 1582 1582 out.vibration.amplitude = amp; 1583 1583 if (duration > 0.00001) { 1584 1584 out.vibration.duration_ns = (time_duration_ns)(duration * 1000.f * 1000.f * 1000.f);