Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

New Input System - Performance

Discussion in 'Input System' started by kalineh, Dec 7, 2021.

  1. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    We are swapping over to the new input system for OpenXR, and taking a look at performance on Quest device, the numbers don't look too great - roughly 0.5ms frame time with two input updates per frame. Trying to get things running at 8.3ms/frame (120hz) means this is a pretty big chunk.

    As a starting point, I just want to ask - is there any settings or best practices we can be looking at to reduce this? Beyond that, what's it doing for 0.5ms? That's a long time to get some input values.

    Is there any streamlined system we could use to just pull the xr controller data struct directly as a byte[] and handle it manually? We are only using a handful of input actions from two controllers + headsets, so we don't need that much complicated data.

    For reference, our input system makes one action map, and binds about 12 input actions in the startup code (once per vr controller). Once per frame we just issue a ReadValue<> from each input action. For the headset & controller, we just have a TrackedPoseDriver (Input System) component , with a single position + rotation.

    (captured with Input System 1.1.1 on unity 2021.2.1f1)
     

    Attached Files:

    Last edited: Dec 7, 2021
    SLGSimon, NotaNaN and AdrielCodeops like this.
  2. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    Looks like this works for getting the raw buffers directly, you just need to dig through the input debugger for all the value & field offsets for specific device.

    EDIT: this layout seemed to work on pc/rift/link but not accurate on device, would have to debug and get the correct layout on device

    Code (CSharp):
    1.     // FourCC: XRS0
    2.     [StructLayout(LayoutKind.Explicit)]
    3.     public struct XRControllerRaw_OculusTouch
    4.     {
    5.         [FieldOffset(0)] public Vector2 thumbstick;
    6.         [FieldOffset(8)] public float grip;
    7.         [FieldOffset(12)] public bool gripPressed;
    8.         [FieldOffset(13)] public bool menu;
    9.         [FieldOffset(14)] public bool primarybutton;
    10.         [FieldOffset(15)] public bool primarytouched;
    11.         [FieldOffset(16)] public bool secondarybutton;
    12.         [FieldOffset(17)] public bool secondarytouched;
    13.         [FieldOffset(20)] public float trigger;
    14.         [FieldOffset(24)] public bool triggerpressed;
    15.         [FieldOffset(25)] public bool triggertouched;
    16.         [FieldOffset(26)] public bool thumbstickclicked;
    17.         [FieldOffset(27)] public bool thumbsticktouched;
    18.         [FieldOffset(36)] public Vector3 devicePosition;
    19.         [FieldOffset(48)] public Quaternion deviceRotation;
    20.         [FieldOffset(76)] public Vector3 angularVelocity;
    21.         [FieldOffset(96)] public Vector3 pointerPosition;
    22.         [FieldOffset(108)] public Quaternion pointerRotation;
    23.         [FieldOffset(148)] public bool istracked;
    24.         [FieldOffset(156)] public byte haptic;
    25.         [FieldOffset(152)] public int trackingstate;
    26.  
    27.         public void Read(InputDevice device)
    28.         {
    29.             Debug.Assert(device != null);
    30.             Debug.Assert(device.deviceId != InputDevice.InvalidDeviceId);
    31.             Debug.Assert(device.stateBlock.format == new UnityEngine.InputSystem.Utilities.FourCC("XRS0"));
    32.  
    33.             unsafe {
    34.                 fixed (void* buffer = &this) {
    35.                     device.ReadValueIntoBuffer(buffer, device.valueSizeInBytes);
    36.                 }
    37.             }
    38.         }
    39.     }
     
    Last edited: Dec 14, 2021
  3. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    Pulling direct from buffers doesn't really seem to improve performance, looks like it's all in the per-frame system updates. Digging through the package source there's a crazy amount of stuff going on. Not sure if there's any feasible way to turn it all off and just get raw devices & buffers for a very small subset of things.
     

    Attached Files:

  4. Warmacha

    Warmacha

    Joined:
    Dec 13, 2015
    Posts:
    27
    We're actually seeing crazy bad performance issues even when dealing with Touchscreens too. It seems like it is constantly doing extra checks when it doesn't need too, and with no way for us to easily touch the code in the package, We haven't found a way to optimize it to not constantly fire unnecessary events.

    In our case, every time you put an extra finger on the touchscreen, it adds more overhead to the cpu. If you have 4 fingers on the screen at once, we're seeing as much as 20 milliseconds of lag, Even if we're only tracking one touch in our game.
    NewInputSpikes.PNG
     
    funkyCoty, kalineh and NotaNaN like this.
  5. Pyr3z

    Pyr3z

    Joined:
    Jul 6, 2017
    Posts:
    32
    @Warmacha

    What kind of devices are you seeing this perf hit for? Mobile, tablet, desktop? Integrated, or peripheral?

    I've been trying to find out if switching to InputSystem for mobile/tablet would be worthwhile, but I can't seem to find many specific hits on the matter. Even if what Warmacha shows is for mobile/tablet, I would still need to run the same tests under InputManager and diff the results in order to make a proper assessment.

    This was Plan A (forum research), but I may have to move on to Plan B: Write custom tests.
     
  6. Warmacha

    Warmacha

    Joined:
    Dec 13, 2015
    Posts:
    27
    This was on an Android device, a Samsung s9. When we compared it to the old input, the new input still had worse performance but the old input isn't without it's performance problems either when it comes to touch input.
     
  7. Justin-Wasilenko

    Justin-Wasilenko

    Joined:
    Mar 10, 2015
    Posts:
    103
    @kalineh Wondering if you have done more testing on this? I was looking at upgrading to the new Input System as well. However am hesitant especially if the performance is worse then the default input system.
     
  8. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    The struct layout didn't seem correct on final builds on device (quest2) compared to editor, and the performance was still just as bad so I didn't bother digging any further. Just another chunk of permanently lost frame time, throw it on the pile.

    Maybe one day I'll be able to just get a memcpy of a couple hundred bytes of data per frame in a reasonable time. If the input state retrieval is even visible on profiler there's a fundamental design error.
     
    funkyCoty and Justin-Wasilenko like this.
  9. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    Come on now

    upload_2022-2-24_11-4-33.png
     
  10. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    752
    Did you make any progress on figuring this out? I am running into the same performance issues on a Quest 2 with the new Input System
     
  11. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    It ended up being about 3ms~ per frame for us when profiling. Looking through the input system source it seems unsalvageable without radically rethought design. I recommend never using it on Quest.

    Just call the OVRPlugin.GetControllerState4() or OVRPlugin.GetNodePoseStateRaw() or whatever and use the values directly. You might need to flip the position values (+x,+y,-z) and the orientation values (-x,-y,+z,+w) because it's not the same space as unity. We did that change and now our input code is 0.00ms on profiler.

    We still use the input system on PC because it can afford to waste that much time, and there's more headset configurations to deal with, but just #ifdef UNITY_ANDROID and get the direct values for Quest.
     
  12. SimonEnvisionVR

    SimonEnvisionVR

    Joined:
    Dec 13, 2020
    Posts:
    9
    I just want to add to this thread to say I recently upgraded my project from the Old Input System to the New Input System.

    It tanked my fps by 70% and I was following recommended optimisations. The only difference in my script was changing Input.GetKey (old system) to input.ReadValue<float>() (new system) which was enough to wipe out 430 frames per second.

    Needless to say I reverted back to the old system. I don't see too much value in this newer system for now, as I don't plan to have cross platform play.
     
  13. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    Has anyone opened a bug report, or can anyone open one if they still have the issue?
     
  14. kalineh

    kalineh

    Joined:
    Dec 23, 2015
    Posts:
    240
    Submitted a bug report:
    CASE IN-15899

    We haven't reverted back because the direct oculus calls takes basically 0ms on device so all that input system code would be a guaranteed loss.
     
    The_Island likes this.
  15. cristofer-oswald

    cristofer-oswald

    Joined:
    Oct 29, 2019
    Posts:
    9
    I am seeing this problem too.
    My current target is mobile, and the performance degradation scales with how many touches happen. This is even noticeble in the editor when using clicks as touches.

    This image is profiling on a high end Android device (with FPS locked at 30). image.png

    Another clear example of the scaling with touches. image (1).png

    Currently we have little to no input processing. We only have a virtual (on screen) joystick that is mapped to the left analog joystick and there is a deadzone configured, then, the inputs are read on the update function.

    This is looking like a really bad problem for low end devices.
     
  16. Jimbaceo

    Jimbaceo

    Joined:
    Nov 21, 2020
    Posts:
    1
    I have experienced something similar with joysticks on windows pc. But it only happens on certain occasions, when it happens to me I usually reboot and it works correctly again. Any update on this issue?
     
  17. AlexRoseGames

    AlexRoseGames

    Joined:
    Jul 13, 2015
    Posts:
    36
    any news on this? looking at a Nintendo Switch game right now and just touching the stick adds 12 milliseconds. 12. Milliseconds. That's 3 quarters of the frame budget if I want to target 60fps

    is there any way I can remove these "process control states"? I really don't want to have to rewrite input from scratch for the platform and read the values directly but what even is this, seriously? how can the frame rate go from 60 to almost 30 just by touching the joystick

    milliseconds.png
     
    Lars-Steenhoff likes this.