Partially deprecated. The frame-correlation technique described in this article relies on
XGameStreamingGetAssociatedFrame and XGameStreamingGetLastFrameDisplayed, which are deprecated as of the 2604 GDK release and will be removed in a future release. The general latency measurement API XGameStreamingGetStreamAddedLatency remains available. See Game streaming latency measurement for latency-aware techniques that don’t depend on frame correlation.
Latency compensation
To compensate for latency in examples as shown in figure 1, games have records of its previous states. When the user presses the jump button, the game searches for that point in the game to determine if the user pressed the button at the right time from their perspective. The key to correct latency compensation is knowing how far into the past to search. The XBOX Game Streaming APIs enable several options for that.Average latency
The simplest, but least accurate, approach for some scenarios is to use the average latency. The XGameStreamingGetStreamAddedLatency API returns a recent average of the latency that’s added by streaming. That average is split into input latency and output latency. Input latency is the time it takes for a user input to be received by the server, and output latency is the time it takes for a video frame that’s rendered by the game to be received and processed by the client device. For time-based actions, a game can use this average as an estimate of when an action occurred. However, network latency can vary, even frame-to-frame, so this approach is imprecise. Additionally, the stream-added latency measurements don’t include non-streaming portions of latency, such as the amount of time the game takes to run simulations and render.Frame tokens with input
The XGameStreamingGetAssociatedFrame API helps solve this problem by providing precise information about the game state the user saw when they pressed a button (or changed any other input). When a frame begins, games using Microsoft Game Development Kit (GDK) callID3D12Device::WaitFrameEventX and receive a D3D12XBOX_FRAME_PIPELINE_TOKEN. You can use D3D12XBOX_FRAME_PIPELINE_TOKEN as a key to save the current state for later in a data structure of your choice, such as a hash map. When the frame is complete, the game calls PresentX with the token.
PresentX ensures that the token is automatically sent to the game streaming client, along with the matching video frame.
Input that’s sent to the server is accompanied with the token for the frame that’s currently displayed on the client. When the game receives an IGameInputReading, you can pass it to the XGameStreamingGetAssociatedFrame API to get the token back. You can use that to look up the previous state and handle the input based on that stored state.
If an input hasn’t changed (because the user isn’t touching the controller, or because they’re just holding a button), there won’t be a new token.
Frame tokens without input
In some cases, you must know what the user has seen most recently, even if their input didn’t change. Returning to the example shown in figure 1, when the character reaches the end of the conveyor belt, they fall. Part of the challenge and fairness of a game is reacting within those time windows. Ideally, a streaming user will have exactly as long to react as a non-streaming user. Because of latency, the ending time of the window should be shifted so that inputs that are received at the end of the window are accepted. To do that, the game can use latency tokens where a button was not pressed. If an input reading with no action matches the state from the end of the window, the user failed to react, and the game can fairly penalize them. The XGameStreamingGetLastFrameDisplayed API returns theD3D12XBOX_FRAME_PIPELINE_TOKEN for the frame that the streaming client displayed most recently. Since it’s constantly updating, you can call it any time and see if the user has seen the end of an animation.
It’s possible to use
XGameStreamingGetLastFrameDisplayed in the same way as XGameStreamingGetAssociatedFrame. We recommend that you use XGameStreamingGetAssociatedFrame when processing input because it returns the token that was on the screen when that input occurred. If more time has passed XGameStreamingGetLastFrameDisplayed might return a token from a more recent frame.