Jump to content

Xytovl

Verified Members
  • Posts

    5
  • Joined

  • Last visited

Reputation

1 Neutral
  1. I have odd behaviour since this update in xrLocateHandJointsEXT: When controller is active since start of application, xrLocateHandJointsEXT returns isActive=true, locationFlags has XR_SPACE_LOCATION_POSITION_VALID_BIT but values appear to not be initialized. Repro code: std::optional<std::array<xr::hand_tracker::joint, XR_HAND_JOINT_COUNT_EXT>> xr::hand_tracker::locate(XrSpace space, XrTime time) { if (!id || !xrLocateHandJointsEXT) return std::nullopt; XrHandJointsLocateInfoEXT info{ .type = XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, .next = nullptr, .baseSpace = space, .time = time, }; std::array<XrHandJointLocationEXT, XR_HAND_JOINT_COUNT_EXT> joints_pos; std::array<XrHandJointVelocityEXT, XR_HAND_JOINT_COUNT_EXT> joints_vel; XrHandJointVelocitiesEXT velocities{ .type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT, .next = nullptr, .jointCount = joints_vel.size(), .jointVelocities = joints_vel.data(), }; XrHandJointLocationsEXT locations{ .type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT, .next = &velocities, .jointCount = joints_pos.size(), .jointLocations = joints_pos.data(), }; CHECK_XR(xrLocateHandJointsEXT(id, &info, &locations)); if (!locations.isActive) return std::nullopt; std::array<xr::hand_tracker::joint, XR_HAND_JOINT_COUNT_EXT> joints; for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { joints[i] = {joints_pos[i], joints_vel[i]}; if (not (joints_pos[i].locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)) spdlog::warn("isActive but joints_pos[{}] position invalid", i); else { if (std::isnan(joints_pos[i].pose.position.x)) spdlog::warn("joints_pos[{}].x is nan", i); if (std::isnan(joints_pos[i].pose.position.y)) spdlog::warn("joints_pos[{}].y is nan", i); if (std::isnan(joints_pos[i].pose.position.z)) spdlog::warn("joints_pos[{}].z is nan", i); } if (not (joints_pos[i].locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) spdlog::warn("isActive but joints_pos[{}] orientation invalid", i); else { if (std::isnan(joints_pos[i].pose.orientation.x)) spdlog::warn("joints_pos[{}].orientation.x is nan", i); if (std::isnan(joints_pos[i].pose.orientation.z)) spdlog::warn("joints_pos[{}].orientation.z is nan", i); if (std::isnan(joints_pos[i].pose.orientation.y)) spdlog::warn("joints_pos[{}].orientation.y is nan", i); if (std::isnan(joints_pos[i].pose.orientation.w)) spdlog::warn("joints_pos[{}].orientation.w is nan", i); } } return joints; } Sample output:
  2. Today's update improved xrLocateSpace a lot! This is a great improvement. xrLocateSpace isn't even visible in the flamechart now. xrLocateViews could still have some optimizations, as I don't see a reason for it to be more complex than locate spaces or hands. Have there been any investigation on the time taken by compositor? Even on simple applications such as hello_xr, xrWaitFrame reports predicted display time 15ms more in the future compared to Quest 1.
  3. I'd like to stress the other very important point for me: when calling xrWaitFrame, the returned predictedDisplayTime in frameState is about 15ms more in the future on Wave runtime compared to Quest. This in turns forces the application to query view and controller pose 15ms more in the future and leads to greatly reduced accuracy. On Vive XR elite, it is consistently 40-41ms at 90Hz refresh rate, on Quest 1 it is in the 23-28ms range at 72Hz refresh rate. Data obtained by adding a log in https://github.com/Meumeu/WiVRn/blob/4c9f24499eb9bbea3c8949e026b6177e19e7c1a3/client/application.cpp#L1056 and comparing predicted time with value from https://github.com/Meumeu/WiVRn/blob/4c9f24499eb9bbea3c8949e026b6177e19e7c1a3/client/xr/instance.cpp#L217
  4. I'd like to get feedback from HTC about xrLocateSpace. Here are flamecharts from the thread dedicated to tracking. Quest 1: HTC XR elite: As a first note, the thread has a throttling mechanism and attempts to be idle 80% of the time, and will reduce the polling frequency in an attempt to reach it, but no less than one sample each 5ms. On Quest, polling is under 2ms and the idle time of 80% is respected. XR Elite is at 5ms polling interval and cannot reach the idle time target. Raw data from capture are wivrn-v0.16-quest1.trace wivrn-v0.16-htc-xr-elite.trace I do not know the internals of Wave runtime, but the performance difference is significant, this also causes the fan to throttle up. Are there any plans to improve this area?
  5. I am developing an OpenXR streaming application for Linux, https://github.com/Meumeu/WiVRn/ and noticed performance and conformance issues on Wave runtime compared to Oculus runtime. Composition layer blending If we don't initialize the alpha channel bit in projection layers, they would not show on the headset, although it would be visible in video. https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#composition-layer-blending states: Vulkan validation layers When running with vulkan validation layers, the runtime generates xrLocateViews viewCapacityInput Calling xrLocateViews with a viewCapacityInput set to 0 takes about the same time as with a value of 2. When using generic code that first calls with 0 then uses the right number of views, this doubles the required time. JNI calls Many OpenXR functions in the wave runtime perform JNI calls, if AttachCurrentThread was not called by the application for the thread, this has a noticeable performance penalty. OpenXR specification does not require applications to do such a call, and no documentation states it. xrLocateSpace performance The xrLocateSpace function performs significantly worse on Wave runtime compared to Meta Quest, a single call is about 30µs on Quest compared to 400 on Wave. Android profiler shows that a significant portion of the time (about 1/6th of xrLocateSpace) is spent in string operations. The same input polling loop is idle 86% of the time (polling rate of 1ms) on Quest, while on Wave, application needs to reduce polling rate up to 5ms for a 50% idle time. Network consistency The application requires very consistent network, we acquire the low latency wifi lock using Android API. UDP packets from headset to PC appear to have an irregular pacing and arrive in bursts. Sometimes there is not packet incoming, for durations up to 50ms Compositor performance Compared to Oculus Quest 1, at the same display resolution, the predicted display time is about 15ms higher on Vive XR elite. Overall result Controller-to-photons latency (ms) over time for Quest 1 (left) and Vive XR elite (right) Distribution of controller-to-photons for Quest 1 (left) and Vive XR elite (right). x axis is the latency in ms, y axis the number of samples. From those plots, we can see that total latency is about 15ms more on Vive XR elite, which according to my measurements is mostly in Wave runtime, as a higher predictedDisplayTime value. We also see that large values are both larger and more frequent, which is caused by controller data not reaching the PC, and therefore older predictions are used. Bonus benchmark A totally scientific benchmark I used is Beat Saber native on Quest, streamed on Quest and streamed on Vive XR elite, on the same level, scores are 200k (Quest native), 186k (Quest streaming) and 130k (Vive XR elite streaming). What I am expecting from this post: Fixes from Vive team on the OpenXR runtime performance and non-conformance issues. Tweaks if any to reduce the predicted display time at the time of xrWaitFrame. Help to investigate the network pattern.
×
×
  • Create New...