Listes de commandes de prise en charge

Cette section s’applique uniquement à Windows 7 et versions ultérieures, ainsi qu’à Windows Server 2008 R2 et versions ultérieures de Windows.

Le runtime Direct3D utilise la DDI Direct3D 11 suivante pour les listes de commandes :

La sémantique des fonctions CommandListExecute, CalcPrivateCommandListSize, CreateCommandList et DestroyCommandList du pilote est principalement explicite, basée sur d’autres fonctions DDI similaires et la documentation de l’API pour la DDI correspondante.

Une fois que le runtime Direct3D a correctement appelé la fonction CreateCommandList ou RecycleCreateCommandList du pilote sur le contexte différé spécifié dans le membre hDeferredContext de la structure D3D11DDIARG_CREATECOMMANDLIST vers laquelle pointe le paramètre pCreateCommandList , le runtime Direct3D exécute la séquence de destruction suivante sur le contexte différé :

  1. Le runtime Direct3D « ferme » tous les handles d’objets différés ouverts. Notez que ces handles peuvent toujours apparaître liés au contexte différé.

  2. Le runtime détruit le contexte différé.

Pendant l’appel à CreateCommandList ou RecycleCreateCommandList, tous les appels effectués par le pilote aux fonctions de rappel DDI d’actualisation d’état continuent de divulguer l’état actuel du contexte différé. Toutefois, pendant la « fermeture » et la destruction du contexte différé, tous les appels à la DDI d’actualisation d’état reflètent que rien n’est lié (c’est-à-dire, immédiatement après l’appel à CreateCommandList ou RecycleCreateCommandList, tout est implicitement indépendant).

Un contexte différé peut également être abandonné explicitement par l’application ou en raison d’une condition d’erreur de la part de l’API ou du pilote. Dans ce cas, le runtime Direct3D effectue la séquence suivante :

  1. Le runtime Direct3D appelle la fonction AbandonCommandList du pilote.

  2. Le runtime dissocie les handles du contexte différé un par un.

  3. Le runtime « ferme » tous les handles d’objets différés ouverts.

  4. Le runtime recyle ou détruit le contexte différé.

La séquence précédente est similaire à la séquence de destruction d’un contexte immédiat. L’appel à la fonction AbandonCommandList du pilote permet au pilote d’appliquer l’état à ce qu’il préfère.

Pendant l’appel à la fonction CommandListExecute du pilote, le pilote doit faire passer l’état du contexte différé pour qu’il corresponde à l’état de création de l’appareil. Cette opération est également appelée opération d’état en clair. Toutefois, pendant l’appel à la fonction CommandListExecute du pilote, tous les appels effectués par le pilote aux fonctions de rappel DDI d’actualisation d’état reflètent toujours l’état de ce qui a été lié lors du dernier appel DDI à une fonction de pilote. Lors de l’appel DDI suivant à une fonction de pilote, tous les appels effectués par le pilote aux fonctions de rappel DDI d’actualisation d’état affichent l’état actuel comme complètement vide, ce qui reflète la transition d’état implicite à partir de CommandListExecute. Ce fait diffère légèrement de la sémantique et du comportement typiques des fonctions de rappel DDI d’actualisation d’état. Si le pilote avait appelé une fonction de rappel DDI d’actualisation d’état lors d’un appel à l’une des fonctions SetShader du pilote, la fonction de rappel DDI d’actualisation d’état affiche comme déjà lié le nouveau nuanceur lié. Cette divergence du comportement de rappel DDI d’actualisation d’état offre plus de flexibilité au pilote pour refléter l’ancien état pendant CommandListExecute.

L’API Direct3D version 11 garantit qu’aucune requête n’a été manipulée (c’est-à-dire que QueryBegin ou QueryEnd a été appelée) par la liste de commandes et qu’elle n’a été « démarrée » que par le contexte qui tente d’exécuter la liste de commandes. L’API garantit également qu’aucune liste de commandes qui a enregistré la carte d’une ressource dynamique n’est exécutée sur un contexte où la même ressource est actuellement mappée. Avant qu’une application appelle la fonction FinishCommandList , le runtime Direct3D appelle la fonction DDI QueryEnd et ResourceUnmap du pilote sur n’importe quelle requête ou ressource dynamique qui contient toujours une requête commencée ou une ressource mappée ouverte, car FinishCommandList termine implicitement les plages de requêtes et annule le mappage de toute ressource mappée.

Optimisation pour les petites listes de commandes

Une optimisation du recyclage de la mémoire pour les listes de commandes de petite quantité de mémoire peut être importante pour réduire la contention entre les appels de fonction DDI de liste de commandes et pour réduire la surcharge de traitement des appels requise pour les listes de commandes. La surcharge de traitement qui est impliquée dans chaque liste de commandes est importante. Cette optimisation est destinée aux listes de commandes où la surcharge de traitement requise pour les listes de commandes domine le temps processeur et l’espace mémoire requis pour les listes de commandes. Une liste de commandes de petite quantité de mémoire est, par exemple, une seule commande graphique, comme CopyResource. La quantité de mémoire requise pour CopyResource est de deux pointeurs. Toutefois, CopyResource nécessite toujours la même quantité de traitement des appels de liste de commandes qu’une liste de commandes volumineuse en mémoire. Lorsque des listes de commandes de petite quantité de mémoire sont générées à une fréquence élevée, la surcharge de traitement requise pour le runtime pour appeler les fonctions CreateCommandList, DestroyCommandList, CreateDeferredContext et DestroyDevice(D3D10) du pilote (pour le contexte différé) devient de plus en plus importante. La mémoire référencée ici est la mémoire système qui contient des structures de données de pilote, qui inclut la mémoire pour les handles DDI.

La fonction RecycleCommandList du pilote doit avertir le pilote lorsque les handles de pilote sont hors d’usage (mais ne sont pas encore supprimés) et lorsque des handles de pilote précédemment inutilisés sont réutilisés. Cette notification s’applique aux handles de liste de commandes et de contexte différé. La seule mémoire que le pilote doit recycler est la mémoire vers laquelle pointe le handle DDI. Bien que l’objectif de RecycleCommandList soit de recycler la mémoire associée au handle, par souci d’efficacité, le pilote dispose d’une flexibilité totale pour choisir la mémoire à recycler. Le pilote ne peut pas modifier la taille de la région de mémoire sur laquelle la liste de commandes de contexte immédiat gère les points. Cette taille est la valeur de retour de CalcPrivateCommandListSize. Le pilote ne peut pas non plus modifier la taille de la région de mémoire vers laquelle la commande de contexte répertorie les points de handle local. Cette taille est la valeur de retour de CalcDeferredContextHandleSize.

Les fonctions DDI RecycleCreateCommandList et RecycleCreateDeferredContext du pilote doivent retourner des codes d’erreur mémoire insuffisante en tant que valeurs HRESULT E_OUTOFMEMORY. Ces fonctions ne fournissent pas de tels codes d’erreur par le biais d’appels à la fonction pfnSetErrorCb . Cette exigence de pilote empêche le runtime d’avoir à utiliser la synchronisation à l’échelle du périphérique pour watch pour les erreurs de contexte immédiates de ces fonctions de pilote de type de création. La surveillance de ces erreurs serait une source de contention catastrophique pour les listes de commandes de petite quantité de mémoire.

Les distinctions entre les fonctions RecycleDestroyCommandList, RecycleCommandList et RecycleCreateCommandList du pilote sont importantes. Leurs fonctionnalités sont les suivantes.

RecycleDestroyCommandList

Le runtime appelle la fonction RecycleDestroyCommandList du pilote pour informer le pilote qu’une destruction légère est nécessaire. Autrement dit, le pilote ne doit pas encore désallouer la mémoire pour le handle de liste de commandes DDI. La fonction RecycleDestroyCommandList du pilote est à thread libre, tout comme la fonction DestroyCommandList du pilote.

RecycleCommandList

La fonction RecycleCommandList du pilote informe le pilote que le runtime a intégré un handle de liste de commandes dans le cache de contexte différé. La fonction permet ensuite au pilote d’intégrer de nouveau la mémoire associée à la liste de commandes dans le cache de contexte différé. Le runtime appelle la fonction RecycleCommandList du pilote à partir du thread de contexte différé. La fonction DDI RecycleCommandList réduit la nécessité pour le pilote d’effectuer sa propre synchronisation.

RecycleCreateCommandList

Le runtime appelle la fonction RecycleCreateCommandList du pilote pour rendre complètement valide un handle DDI précédemment inutilisé.

Ces fonctions DDI de recyclage offrent des opportunités d’optimisation pour aider à recycler les ressources pour les listes de commandes de petite quantité de mémoire. Le pseudo-code suivant montre l’implémentation du runtime via le flux d’appels de fonction de l’API vers la DDI :

::FinishCommandList()
{
  // Empty InterlockedSList, integrating into the cache
  Loop { DC::pfnRecycleCommandList }

  If (Previously Destroyed CommandList Available)
 { IC::pfnRecycleCreateCommandList }
 else
  {
    IC::pfnCalcPrivateCommandListSize
    IC::pfnCreateCommandList
    IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
  }

  Loop { DC::pfnDestroy* (context-local handle destroy) }

  IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)

CommandList::Destroy()
{
  // If DC still alive, almost always recycle:
  If (DC still alive)
 { IC::pfnRecycleDestroyCommandList }
  Else
 { IC::pfnDestroyCommandList }
  // Add to InterlockedSList
}

Le diagramme d’état suivant montre la validité d’un handle de liste de commandes DDI dans le contexte immédiat. L’état vert représente un handle qui peut être utilisé avec CommandListExecute.

Diagramme illustrant les états de validité d’un handle de liste de commandes DDI dans le contexte immédiat.