Réduire la latence avec des chaînes de permutation DXGI 1.3

Applies to Windows only

Utilisez DXGI 1.3 afin de réduire la latence d’image effective en attendant que la chaîne de permutation indique le moment approprié pour débuter le rendu d’une nouvelle image. Normalement, les jeux doivent offrir la latence la plus faible possible entre le moment où l’entrée du joueur est reçue et le moment où le jeu répond à cette entrée en mettant à jour l’affichage. Cette rubrique décrit une technique disponible à partir de Direct3D 11.2, qui vous permet de réduire la latence d’image effective dans votre jeu.

Comment la mise en file d’attente en mémoire tampon d’arrière-plan peut-elle réduire la latence ?

Avec la chaîne de permutation de modèle de retournement, les « retournements » de la mémoire tampon d’arrière-plan sont placés en file d’attente chaque fois que votre jeu appelle IDXGISwapChain::Present. Quand la boucle de rendu appelle Present(), le système bloque le thread jusqu’à ce qu’il ait fini de présenter une image précédente, ce qui libère de l’espace pour la mise en file d’attente de la nouvelle image, avant la présentation réelle. Cela entraîne une latence supplémentaire entre le moment où le jeu dessine une image et le moment où le système lui permet d’afficher cette image. Bien souvent, le système atteint un état d’équilibre quand le jeu attend une image supplémentaire complète entre le moment du rendu et la présentation de chaque image. Il est préférable d’attendre que le système soit prêt à accepter une nouvelle image, puis d’effectuer le rendu en fonction des données actuelles et de mettre immédiatement l’image en file d’attente.

Créez une chaîne de permutation d’attente avec l’indicateur DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT. Les chaînes de permutation créées de cette manière peuvent informer votre boucle de rendu, une fois que le système est prêt à accepter une nouvelle image. Cela permet à votre jeu d’effectuer le rendu en fonction des données actuelles, puis de placer le résultat immédiatement en file d’attente de présentation.

Cette procédure pas à pas utilise le code de l’exemple DirectXLatency.

Étape 1 : créer une chaîne de permutation d’attente

Spécifiez l’indicateur DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT quand vous appelez CreateSwapChainForCoreWindow.


swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; // Enable GetFrameLatencyWaitableObject().


Remarque  Contrairement à certains indicateurs, cet indicateur ne peut pas être ajouté ou retiré via ResizeBuffers. DXGI retourne un code d’erreur si cet indicateur n’est pas le même qu’au moment où la chaîne de permutation a été créée.


// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain->ResizeBuffers(
    2, // Double-buffered swap chain.
    static_cast<UINT>(m_d3dRenderTargetSize.Width),
    static_cast<UINT>(m_d3dRenderTargetSize.Height),
    DXGI_FORMAT_B8G8R8A8_UNORM,
    DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT // Enable GetFrameLatencyWaitableObject().
    );


Étape 2 : définir la latence de l’image

Définissez la latence de l’image avec l’API IDXGISwapChain2::SetMaximumFrameLatency, au lieu d’appeler IDXGIDevice1::SetMaximumFrameLatency.

Par défaut, la valeur de la latence d’image pour les chaînes de permutation d’attente est égale à 1, ce qui correspond à la latence la plus faible. Toutefois, cela réduit également le parallélisme entre l’UC et l’unité de traitement graphique. Si vous avez besoin d’un parallélisme plus important entre l’UC et l’unité de traitement graphique afin d’atteindre 60 images par seconde (en d’autres termes, si l’UC et l’unité de traitement graphique consacrent chacune moins de 16,7 ms au rendu d’une image, mais qu’elles consacrent à elles deux plus de 16,7 ms), affectez la valeur 2 à la latence d’image. Cela permet à l’unité de traitement graphique de traiter les travaux mis en file d’attente par l’UC durant le traitement de l’image précédente, tout en permettant à l’UC d’envoyer les commandes de rendu de l’image actuelle de façon indépendante.


// Swapchains created with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag use their
// own per-swapchain latency setting instead of the one associated with the DXGI device. The
// default per-swapchain latency is 1, which ensures that DXGI does not queue more than one frame
// at a time. This both reduces latency and ensures that the application will only render after
// each VSync, minimizing power consumption.
//DX::ThrowIfFailed(
//    swapChain2->SetMaximumFrameLatency(1)
//    );


Étape 3 : obtenir l’objet d’attente de la chaîne de permutation

Appelez IDXGISwapChain2::GetFrameLatencyWaitableObject pour récupérer le handle d’attente. Le handle d’attente est un pointeur vers l’objet d’attente. Conservez ce handle afin qu’il soit utilisé par votre boucle de rendu.


// Get the frame latency waitable object, which is used by the WaitOnSwapChain method. This
// requires that swap chain be created with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
// flag.
m_frameLatencyWaitableObject = swapChain2->GetFrameLatencyWaitableObject();


Étape 4 : attendre avant d’effectuer le rendu de chaque image

Votre boucle de rendu doit attendre le signal de la chaîne de permutation via l’objet d’attente avant de commencer à effectuer le rendu de chaque image. Cela inclut la première image rendue avec la chaîne de permutation. Utilisez WaitForSingleObjectEx, en fournissant le handle d’attente récupéré à l’étape 2, pour signaler le début de chaque image.

L’exemple suivant montre la boucle de rendu de l’exemple DirectXLatency :


while (!m_windowClosed)
{
    if (m_windowVisible)
    {
        // Block this thread until the swap chain is finished presenting. Note that it is
        // important to call this before the first Present in order to minimize the latency
        // of the swap chain.
        m_deviceResources->WaitOnSwapChain();

        // Process any UI events in the queue.
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

        // Update app state in response to any UI events that occurred.
        m_main->Update();

        // Render the scene.
        m_main->Render();

        // Present the scene.
        m_deviceResources->Present();
    }
    else
    {
        // The window is hidden. Block until a UI event occurs.
        CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
    }
}


L’exemple suivant montre l’appel de WaitForSingleObjectEx à partir de l’exemple DirectXLatency :


// Block the current thread until the swap chain has finished presenting.
void DX::DeviceResources::WaitOnSwapChain()
{
    DWORD result = WaitForSingleObjectEx(
        m_frameLatencyWaitableObject,
        1000, // 1 second timeout (shouldn't ever occur)
        true
        );
}


Que doit faire mon jeu pendant qu’il attend la présentation de la chaîne de permutation ?

Si votre jeu n’a aucune tâche qui bloque la boucle de rendu, il peut être judicieux de le laisser attendre la présentation de la chaîne de permutation, car cela permet d’économiser de l’énergie, ce qui est particulièrement important sur les appareils mobiles. Sinon, utilisez le multithreading pour exécuter le travail pendant que votre jeu attend la présentation de la chaîne de permutation. Voici quelques tâches que votre jeu peut effectuer :

  • Traitement des événements réseau
  • Mise à jour de l’IA
  • Calculs de physique basés sur l’UC
  • Rendu de contexte différé (sur les appareils compatibles)
  • Chargement de ressources

Pour plus d’informations sur la programmation multithread dans Windows, voir les rubriques connexes suivantes.

Rubriques associées

Exemple DirectXLatency
IDXGISwapChain2::GetFrameLatencyWaitableObject
WaitForSingleObjectEx
Windows.System.Threading
Programmation asynchrone en C++
Processus et threads
Synchronisation
Utilisation d’objets Event (Windows)

 

 

Afficher:
© 2014 Microsoft