Optimieren der Eingabelatenz für UWP-DirectX-Spiele (Universelle Windows-Plattform)Optimize input latency for Universal Windows Platform (UWP) DirectX games

Die Eingabelatenz kann das Spielerlebnis erheblich beeinträchtigen. Spiele wirken professioneller, wenn in diesem Bereich eine Optimierung vorgenommen wird.Input latency can significantly impact the experience of a game, and optimizing it can make a game feel more polished. Außerdem kann eine richtige Optimierung der Eingabeereignisse zu einer besseren Akkulaufzeit führen.Additionally, proper input event optimization can improve battery life. Hier erfahren Sie, wie Sie die richtigen Verarbeitungsoptionen für CoreDispatcher-Eingabeereignisse auswählen, um sicherzustellen, dass die Eingaben im Spiel so reibungslos wie möglich verarbeitet werden.Learn how to choose the right CoreDispatcher input event processing options to make sure your game handles input as smoothly as possible.

EingabelatenzInput latency

Die Eingabelatenz ist der Zeitraum, den das System benötigt, um auf Benutzereingaben zu reagieren.Input latency is the time it takes for the system to respond to user input. Die Reaktion ist häufig eine Änderung der Anzeige auf dem Bildschirm oder der Audioausgabe.The response is often a change in what's displayed on the screen, or what's heard through audio feedback.

Jedes Eingabeereignis – ob über einen Toucheingabezeiger, einen Mauszeiger oder eine Tastatur – generiert eine Nachricht, die von einem Ereignishandler bearbeitet wird.Every input event, whether it comes from a touch pointer, mouse pointer, or keyboard, generates a message to be processed by an event handler. Moderne Touchdigitalisierungsgeräte und Gaming-Peripheriegeräte melden Eingabeereignisse mit mindestens 100 Hz pro Zeiger. Dies bedeutet, dass Ihre App pro Sekunde pro Zeiger (oder Tastaturanschlag) mindestens 100 Ereignisse empfangen kann.Modern touch digitizers and gaming peripherals report input events at a minimum of 100 Hz per pointer, which means that apps can receive 100 events or more per second per pointer (or keystroke). Diese Aktualisierungsrate wird noch verstärkt, wenn mehrere Zeiger gleichzeitig oder ein Eingabegerät mit höherer Präzision (z. B. eine Gamingmaus) verwendet werden.This rate of updates is amplified if multiple pointers are happening concurrently, or a higher precision input device is used (for example, a gaming mouse). Die Warteschlange für Ereignismeldungen kann sich also sehr schnell füllen.The event message queue can fill up very quickly.

Es ist wichtig, dass Sie für Ihr Spiel die Anforderungen an die Eingabelatenz verstehen, damit Ereignisse für den jeweiligen Fall auf bestmögliche Weise verarbeitet werden.It's important to understand the input latency demands of your game so that events are processed in a way that is best for the scenario. Es gibt keine Standardlösung für alle Spiele.There is no one solution for all games.

Effiziente Nutzung der EnergiePower efficiency

Im Zusammenhang mit der Eingabelatenz geht es bei der effizienten Nutzung der Energie darum, wie stark die GPU vom Spiel genutzt wird.In the context of input latency, "power efficiency" refers to how much a game uses the GPU. Ein Spiel, bei dem weniger GPU-Ressourcen genutzt werden, ist energieeffizienter und ermöglicht eine längere Akkulaufzeit.A game that uses less GPU resources is more power efficient and allows for longer battery life. Dies gilt auch für die CPU.This also holds true for the CPU.

Wenn ein Spiel den gesamten Bildschirm mit weniger als 60 Frames pro Sekunde zeichnen kann (derzeit die maximale Rendergeschwindigkeit der meisten Displays), ohne das Spielerlebnis zu beeinträchtigen, ist die Energieeffizienz höher, weil weniger oft gezeichnet werden muss.If a game can draw the whole screen at less than 60 frames per second (currently, the maximum rendering speed on most displays) without degrading the user's experience, it will be more power efficient by drawing less often. Bei einigen Spielen wird der Bildschirm nur als Reaktion auf Benutzereingaben aktualisiert, sodass die gleichen Inhalte nicht immer wieder mit 60 Frames pro Sekunde gezeichnet werden müssen.Some games only update the screen in response to user input, so those games should not draw the same content repeatedly at 60 frames per second.

Auswählen der OptimierungszieleChoosing what to optimize for

Beim Entwerfen einer DirectX-App müssen Sie einige Entscheidungen treffen.When designing a DirectX app, you need to make some choices. Müssen für die App 60 Frames pro Sekunde gerendert werden, um eine reibungslose Animation zu gewährleisten, oder muss nur als Reaktion auf Eingaben gerendert werden?Does the app need to render 60 frames per second to present smooth animation, or does it only need to render in response to input? Muss die geringstmögliche Eingabelatenz verwendet werden, oder ist eine kurze Verzögerung tolerierbar?Does it need to have the lowest possible input latency, or can it tolerate a little bit of delay? Erwarten die Benutzer, dass bei der App auf die Akkunutzung geachtet wird?Will my users expect my app to be judicious about battery usage?

Die Antworten auf diese Fragen führen für die App in der Regel zu einem der folgenden Fälle:The answers to these questions will likely align your app with one of the following scenarios:

  1. Rendern bei Bedarf:Render on demand. Für Spiele dieser Kategorie muss der Bildschirm nur als Reaktion auf bestimmte Arten von Eingaben aktualisiert werden.Games in this category only need to update the screen in response to specific types of input. Die Energieeffizienz ist sehr gut, weil von der App identische Frames nicht immer wieder gerendert werden, und die Eingabelatenz ist niedrig, da die App die meiste Zeit mit dem Warten auf eine Eingabe verbringt.Power efficiency is excellent because the app doesn’t render identical frames repeatedly, and input latency is low because the app spends most of its time waiting for input. Brettspiele und Newsreader sind Beispiele für Apps, die ggf. in diese Kategorie fallen.Board games and news readers are examples of apps that might fall into this category.
  2. Rendern bei Bedarf mit kurzlebigen AnimationenRender on demand with transient animations. Dieser Fall ähnelt dem ersten Fall, mit der Ausnahme, dass bestimmte Arten von Eingaben eine Animation auslösen, die nicht von Folgeeingaben des Benutzers abhängig ist.This scenario is similar to the first scenario except that certain types of input will start an animation that isn’t dependent on subsequent input from the user. Die Energieeffizienz ist gut, weil identische Frames vom Spiel nicht immer wieder gerendert werden, und die Eingabelatenz ist niedrig, während im Spiel keine Animationen aktiv sind.Power efficiency is good because the game doesn’t render identical frames repeatedly, and input latency is low while the game is not animating. Interaktive Spiele für Kinder und Brettspiele, bei denen jeder Zug animiert ist, sind Beispiele für Apps, die ggf. in diese Kategorie fallen.Interactive children’s games and board games that animate each move are examples of apps that might fall into this category.
  3. Rendern von 60 Frames pro Sekunde:Render 60 frames per second. In diesem Fall wird der Bildschirm vom Spiel ständig aktualisiert.In this scenario, the game is constantly updating the screen. Die Energieeffizienz ist nicht gut, weil die maximale Anzahl Frames, die vom Display dargestellt werden kann, gerendert wird.Power efficiency is poor because it renders the maximum number of frames the display can present. Die Eingabelatenz ist hoch, da der Thread während der Darstellung der Inhalte von DirectX blockiert wird.Input latency is high because DirectX blocks the thread while content is being presented. So wird der Thread daran gehindert, mehr Frames an das Display zu senden, als dem Benutzer angezeigt werden können.Doing so prevents the thread from sending more frames to the display than it can show to the user. Ego-Shooter, Echtzeit-Strategiespiele und Spiele auf physischer Basis sind Beispiele für Apps, die ggf. in diese Kategorie fallen.First person shooters, real-time strategy games, and physics-based games are examples of apps that might fall into this category.
  4. Rendern von 60 Frames pro Sekunde und Erzielen der geringstmöglichen EingabelatenzRender 60 frames per second and achieve the lowest possible input latency. Die App aktualisiert den Bildschirm, ähnlich wie im dritten Fall, ständig, und die Energieeffizienz ist schlecht.Similar to scenario 3, the app is constantly updating the screen, so power efficiency will be poor. Der Unterschied besteht darin, dass das Spiel über einen separaten Thread auf Eingaben reagiert. Daher wird die Eingabeverarbeitung beim Darstellen von Grafiken auf dem Display nicht blockiert.The difference is that the game responds to input on a separate thread, so that input processing isn’t blocked by presenting graphics to the display. Onlinespiele mit mehreren Spielern, Kampfspiele oder Spiele auf Rhythmus- bzw. Zeitbasis fallen ggf. in diese Kategorie, da Eingaben innerhalb von extrem engen Ereignisfenstern unterstützt werden.Online multiplayer games, fighting games, or rhythm/timing games might fall into this category because they support move inputs within extremely tight event windows.

ImplementierungImplementation

Die meisten DirectX-Spiele basieren auf der so genannten Spielschleife.Most DirectX games are driven by what is known as the game loop. Der grundlegende Algorithmus besteht darin, die folgenden Schritte auszuführen, bis der Benutzer das Spiel oder die App beendet:The basic algorithm is to perform these steps until the user quits the game or app:

  1. Eingabe verarbeitenProcess input
  2. Spielzustand aktualisierenUpdate the game state
  3. Inhalte des Spiels zeichnenDraw the game content

Wenn die Inhalte eines DirectX-Spiels gerendert und bereit für die Darstellung auf dem Bildschirm sind, wartet die Spielschleife, bis die GPU einen neuen Frame empfangen kann, bevor erneut Eingaben verarbeitet werden.When the content of a DirectX game is rendered and ready to be presented to the screen, the game loop waits until the GPU is ready to receive a new frame before waking up to process input again.

Die Implementierung der Spielschleife wird unten für die einzelnen beschriebenen Fälle veranschaulicht, indem der Prozess eines einfachen Puzzlespiels durchlaufen wird.We’ll show the implementation of the game loop for each of the scenarios mentioned earlier by iterating on a simple jigsaw puzzle game. Die Entscheidungspunkte, Vorteile und Nachteile, die Teil jeder Implementierung sind, dienen Ihnen als Unterstützung beim Optimieren Ihrer Apps in Bezug auf eine niedrige Eingabelatenz und eine hohe Energieeffizienz.The decision points, benefits, and tradeoffs discussed with each implementation can serve as a guide to help you optimize your apps for low latency input and power efficiency.

Szenario 1: Bei Bedarf zu rendernScenario 1: Render on demand

Beim ersten Durchlauf des Puzzlespiels wird der Bildschirm nur aktualisiert, wenn ein Benutzer ein Puzzleteil verschiebt.The first iteration of the jigsaw puzzle game only updates the screen when a user moves a puzzle piece. Benutzer können ein Puzzleteil entweder an seinen Platz ziehen oder das Teil auswählen und dann auf die richtige Position tippen.A user can either drag a puzzle piece into place or snap it into place by selecting it and then touching the correct destination. Im letzteren Fall wird das Puzzleteil ohne Animation oder Effekte eingefügt.In the second case, the puzzle piece will jump to the destination with no animation or effects.

Der Code umfasst eine Spielschleife mit einem einzelnen Thread in der IFrameworkView::Run-Methode, für die das CoreProcessEventsOption::ProcessOneAndAllPending-Element verwendet wird.The code has a single-threaded game loop within the IFrameworkView::Run method that uses CoreProcessEventsOption::ProcessOneAndAllPending. Mit dieser Option werden alle derzeit verfügbaren Ereignisse in der Warteschlange verteilt.Using this option dispatches all currently available events in the queue. Falls keine Ereignisse ausstehen, wartet die Spielschleife, bis ein Ereignis vorhanden ist.If no events are pending, the game loop waits until one appears.

void App::Run()
{
    
    while (!m_windowClosed)
    {
        // Wait for system events or input from the user.
        // ProcessOneAndAllPending will block the thread until events appear and are processed.
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);

        // If any of the events processed resulted in a need to redraw the window contents, then we will re-render the
        // scene and present it to the display.
        if (m_updateWindow || m_state->StateChanged())
        {
            m_main->Render();
            m_deviceResources->Present();

            m_updateWindow = false;
            m_state->Validate();
        }
    }
}

Szenario 2: Bei Bedarf mit vorübergehenden Animationen RendernScenario 2: Render on demand with transient animations

Beim zweiten Durchlauf wird das Spiel modifiziert. Wenn Benutzer ein Puzzleteil auswählen und dann auf die richtige Position für das Teil tippen, wird es auf dem Bildschirm per Animation an seine Zielposition verschoben.In the second iteration, the game is modified so that when a user selects a puzzle piece and then touches the correct destination for that piece, it animates across the screen until it reaches its destination.

Wie im ersten Szenario verfügt der Code über eine Spielschleife mit einem einzelnen Thread, die mithilfe von ProcessOneAndAllPending die in der Warteschlange enthaltenen Eingabeereignisse verteilt.As before, the code has a single-threaded game loop that uses ProcessOneAndAllPending to dispatch input events in the queue. Der Unterschied besteht jetzt darin, dass die Schleife während der Animation zu CoreProcessEventsOption::ProcessAllIfPresent, damit nicht auf neue Eingabeereignisse gewartet wird.The difference now is that during an animation, the loop changes to use CoreProcessEventsOption::ProcessAllIfPresent so that it doesn’t wait for new input events. Wenn keine Ereignisse ausstehen, erfolgt die Rückgabe für ProcessEvents sofort, und die App kann den nächsten Frame der Animation darstellen.If no events are pending, ProcessEvents returns immediately and allows the app to present the next frame in the animation. Nachdem die Animation abgeschlossen ist, wechselt die Schleife zurück zu ProcessOneAndAllPending, um die Bildschirmaktualisierungen zu begrenzen.When the animation is complete, the loop switches back to ProcessOneAndAllPending to limit screen updates.

void App::Run()
{

    while (!m_windowClosed)
    {
        // 2. Switch to a continuous rendering loop during the animation.
        if (m_state->Animating())
        {
            // Process any system events or input from the user that is currently queued.
            // ProcessAllIfPresent will not block the thread to wait for events. This is the desired behavior when
            // you are trying to present a smooth animation to the user.
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            m_state->Update();
            m_main->Render();
            m_deviceResources->Present();
        }
        else
        {
            // Wait for system events or input from the user.
            // ProcessOneAndAllPending will block the thread until events appear and are processed.
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);

            // If any of the events processed resulted in a need to redraw the window contents, then we will re-render the
            // scene and present it to the display.
            if (m_updateWindow || m_state->StateChanged())
            {
                m_main->Render();
                m_deviceResources->Present();

                m_updateWindow = false;
                m_state->Validate();
            }
        }
    }
}

Zur Unterstützung des Übergangs zwischen ProcessOneAndAllPending und ProcessAllIfPresent muss der Status von der App nachverfolgt werden, um ermitteln zu können, ob die Animation aktiv ist.To support the transition between ProcessOneAndAllPending and ProcessAllIfPresent, the app must track state to know if it’s animating. In der Puzzle-App fügen Sie dazu eine neue Methode hinzu, die während der Spielschleife für die GameState-Klasse aufgerufen werden kann.In the jigsaw puzzle app, you do this by adding a new method that can be called during the game loop on the GameState class. Der Animationszweig der Spielschleife bewirkt die Aktualisierungen des Animationsstatus, indem die neue Update-Methode für GameState aufgerufen wird.The animation branch of the game loop drives updates in the state of the animation by calling GameState’s new Update method.

Szenario 3: Rendern von 60 Bildern pro SekundeScenario 3: Render 60 frames per second

Beim dritten Durchlauf zeigt die App einen Zeitgeber an, um Benutzern mitzuteilen, wie lange sie bereits an der Lösung des Puzzles gearbeitet haben.In the third iteration, the app displays a timer that shows the user how long they’ve been working on the puzzle. Da die verstrichene Dauer bis auf Millisekunden genau angegeben wird, müssen 60 Frames pro Sekunde gerendert werden, um die Anzeige aktuell zu halten.Because it displays the elapsed time up to the millisecond, it must render 60 frames per second to keep the display up to date.

Wie in den Szenarien 1 und 2 auch, verfügt die App über eine Spielschleife mit einem einzelnen Thread.As in scenarios 1 and 2, the app has a single-threaded game loop. Bei diesem Szenario besteht der Unterschied darin, dass aufgrund des ständigen Renderns keine Änderungen des Spielstatus mehr nachverfolgt werden müssen, wie dies bei den ersten beiden Szenarien der Fall war.The difference with this scenario is that because it’s always rendering, it no longer needs to track changes in the game state as was done in the first two scenarios. Daher kann für die Verarbeitung von Ereignissen standardmäßig ProcessAllIfPresent verwendet werden.As a result, it can default to use ProcessAllIfPresent for processing events. Wenn keine Ereignisse ausstehen, erfolgt die Rückgabe für ProcessEvents sofort, und es wird mit dem Rendern des nächsten Frames fortgefahren.If no events are pending, ProcessEvents returns immediately and proceeds to render the next frame.

void App::Run()
{

    while (!m_windowClosed)
    {
        if (m_windowVisible)
        {
            // 3. Continuously render frames and process system events and input as they appear in the queue.
            // ProcessAllIfPresent will not block the thread to wait for events. This is the desired behavior when
            // trying to present smooth animations to the user.
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            m_state->Update();
            m_main->Render();
            m_deviceResources->Present();
        }
        else
        {
            // 3. If the window isn't visible, there is no need to continuously render.
            // Process events as they appear until the window becomes visible again.
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    }
}

Dieser Ansatz ist die einfachste Möglichkeit, ein Spiel zu schreiben, da für die Ermittlung des Renderzeitpunkts kein weiterer Status nachverfolgt werden muss.This approach is the easiest way to write a game because there’s no need to track additional state to determine when to render. Dabei werden die kürzestmöglichen Renderzeiträume und eine angemessene Reaktionsfähigkeit auf Eingaben pro Timerintervall erzielt.It achieves the fastest rendering possible along with reasonable input responsiveness on a timer interval.

Die Einfachheit dieses Entwicklungsansatzes hat aber auch einen Nachteil.However, this ease of development comes with a price. Beim Rendern mit 60 Frames pro Sekunde wird mehr Energie als beim Rendern bei Bedarf verbraucht.Rendering at 60 frames per second uses more power than rendering on demand. Am besten eignet sich ProcessAllIfPresent, wenn die Anzeige vom Spiel für jeden Frame geändert wird.It’s best to use ProcessAllIfPresent when the game is changing what is displayed every frame. Außerdem wird damit die Eingabelatenz um bis zu 16,7 ms erhöht, da die App die Spielschleife nun während des Synchronisierungsintervalls des Displays und nicht bei ProcessEvents blockiert.It also increases input latency by as much as 16.7 ms because the app is now blocking the game loop on the display’s sync interval instead of on ProcessEvents. Unter Umständen werden einige Eingabeereignisse verworfen, da die Warteschlange nur einmal pro Frame (60 Hz) verarbeitet wird.Some input events might be dropped because the queue is only processed once per frame (60 Hz).

Szenario 4: Rendern von 60 Bildern pro Sekunde und die geringste Eingabe Latenz erzielenScenario 4: Render 60 frames per second and achieve the lowest possible input latency

Bei einigen Spielen kann es möglich sein, den Anstieg der Eingabelatenz aus Szenario 3 zu ignorieren oder auszugleichen.Some games may be able to ignore or compensate for the increase in input latency seen in scenario 3. Wenn eine geringe Eingabelatenz für das Spielerlebnis und die Spielerrückmeldungen aber von entscheidender Bedeutung ist, müssen Spiele, die 60 Frames pro Sekunde rendern, die Eingabe in einem separaten Thread verarbeiten.However, if low input latency is critical to the game’s experience and sense of player feedback, games that render 60 frames per second need to process input on a separate thread.

Der vierte Durchlauf des Puzzlespiels baut auf Szenario 3 auf, indem die Eingabeverarbeitung und das Rendern der Grafiken aus der Spielschleife in separate Threads unterteilt wird.The fourth iteration of the jigsaw puzzle game builds on scenario 3 by splitting the input processing and graphics rendering from the game loop into separate threads. Mit der Nutzung separater Threads wird sichergestellt, dass die Eingabe durch die Grafikausgabe nicht verzögert werden kann. Der Code wird dadurch aber komplexer.Having separate threads for each ensures that input is never delayed by graphics output; however, the code becomes more complex as a result. In Szenario 4 ruft der Eingabethread ProcessEvents mit CoreProcessEventsOption::ProcessUntilQuit auf. Damit wird auf neue Ereignisse gewartet, und alle verfügbaren Ereignisse werden verteilt.In scenario 4, the input thread calls ProcessEvents with CoreProcessEventsOption::ProcessUntilQuit, which waits for new events and dispatches all available events. Dieses Verhalten wird beibehalten, bis das Fenster geschlossen wird oder das Spiel CoreWindow::Close aufruft.It continues this behavior until the window is closed or the game calls CoreWindow::Close.

void App::Run()
{
    // 4. Start a thread dedicated to rendering and dedicate the UI thread to input processing.
    m_main->StartRenderThread();

    // ProcessUntilQuit will block the thread and process events as they appear until the App terminates.
    CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
}

void JigsawPuzzleMain::StartRenderThread()
{
    // If the render thread is already running, then do not start another one.
    if (IsRendering())
    {
        return;
    }

    // Create a task that will be run on a background thread.
    auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction^ action)
    {
        // Notify the swap chain that this app intends to render each frame faster
        // than the display's vertical refresh rate (typically 60 Hz). Apps that cannot
        // deliver frames this quickly should set this to 2.
        m_deviceResources->SetMaximumFrameLatency(1);

        // Calculate the updated frame and render once per vertical blanking interval.
        while (action->Status == AsyncStatus::Started)
        {
            // Execute any work items that have been queued by the input thread.
            ProcessPendingWork();

            // Take a snapshot of the current game state. This allows the renderers to work with a
            // set of values that won't be changed while the input thread continues to process events.
            m_state->SnapState();

            m_sceneRenderer->Render();
            m_deviceResources->Present();
        }

        // Ensure that all pending work items have been processed before terminating the thread.
        ProcessPendingWork();
    });

    // Run the task on a dedicated high priority background thread.
    m_renderLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced);
}

Die DirectX 11 und XAML-App (Universelles Windows) Vorlage in Microsoft Visual Studio 2015 teilt die spielschleife in mehreren Threads auf ähnliche Weise.The DirectX 11 and XAML App (Universal Windows) template in Microsoft Visual Studio 2015 splits the game loop into multiple threads in a similar fashion. Dabei wird das Windows::UI::Core::CoreIndependentInputSource-Objekt verwendet, um einen Thread für die Behandlung der Eingabe zu starten. Außerdem wird ein Renderthread erstellt, der unabhängig vom XAML-UI-Thread ist.It uses the Windows::UI::Core::CoreIndependentInputSource object to start a thread dedicated to handling input and also creates a rendering thread independent of the XAML UI thread. Weitere Informationen zu diesen Vorlagen finden Sie unter Erstellen eines UWP- und eines DirectX-Spieleprojekts aus einer Vorlage.For more details on these templates, read Create a Universal Windows Platform and DirectX game project from a template.

Weitere Möglichkeiten zur Reduzierung der EingabelatenzAdditional ways to reduce input latency

Verwenden von Swapchains mit WartemöglichkeitUse waitable swap chains

DirectX-Spiele reagieren auf Benutzereingaben mit der Aktualisierung der Inhalte, die Benutzer auf dem Bildschirm sehen.DirectX games respond to user input by updating what the user sees on-screen. Bei einem 60 Hz-Display wird der Bildschirm alle 16,7 ms (1 Sekunde/60 Frames) aktualisiert.On a 60 Hz display, the screen refreshes every 16.7 ms (1 second/60 frames). In Abbildung 1 sind der ungefähre Lebenszyklus und die Reaktion auf ein Eingabeereignis relativ zum Aktualisierungssignal nach 16,7 ms (VBlank) für eine App dargestellt, die mit 60 Frames pro Sekunde gerendert wird:Figure 1 shows the approximate life cycle and response to an input event relative to the 16.7 ms refresh signal (VBlank) for an app that renders 60 frames per second:

Abbildung 1Figure 1

Abbildung 1: Eingabelatenz in DirectXfigure 1 input latency in directx

In Windows 8.1, DXGI eingeführt, die DXGI_SWAP_Kette_FLAG_FRAME_LATENZ_WAITABLE_Objekt Flag für den Austausch Kette, bei dem apps ganz einfach diese Latenzen verringert werden, ohne dass diese Heuristiken aus, um die Warteschlange vorhanden leer bleiben implementieren kann.In Windows 8.1, DXGI introduced the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag for the swap chain, which allows apps to easily reduce this latency without requiring them to implement heuristics to keep the Present queue empty. Mit diesem Flag erstellte Swapchains werden als Swapchains mit Wartemöglichkeit bezeichnet.Swap chains created with this flag are referred to as waitable swap chains. Abbildung 2 zeigt den ungefähren Lebenszyklus und die Reaktion auf ein Eingabeereignis bei Verwendung von Swapchains mit Wartemöglichkeit:Figure 2 shows the approximate life cycle and response to an input event when using waitable swap chains:

Abbildung 2Figure 2

Abbildung 2: Eingabelatenz in DirectX mit Wartemöglichkeit

Diese Abbildungen zeigen, dass die Eingabelatenz bei Spielen um zwei volle Frames reduziert werden kann, wenn das Rendern und Darstellen der einzelnen Frames innerhalb des Zeitraums von 16,7 ms durchgeführt werden kann, der durch die Aktualisierungsrate des Displays vorgegeben ist.What we see from these diagrams is that games can potentially reduce input latency by two full frames if they are capable of rendering and presenting each frame within the 16.7 ms budget defined by the display’s refresh rate. Im Beispiel mit dem Puzzle werden Swapchains mit Wartemöglichkeit verwendet, und das Limit der Present-Warteschlange wird per Aufruf des folgenden Elements gesteuert:m_deviceResources->SetMaximumFrameLatency(1);The jigsaw puzzle sample uses waitable swap chains and controls the Present queue limit by calling:m_deviceResources->SetMaximumFrameLatency(1);