Portage de Direct3D 11 vers Direct3D 12

Cette section fournit des conseils sur le portage d’un moteur graphique Direct3D 11 personnalisé vers Direct3D 12.

Création d’appareils

Direct3D 11 et Direct3D 12 partagent un modèle de création d’appareil similaire. Les pilotes Direct3D 12 existants sont tous D3D_FEATURE_LEVEL_11_0 ou mieux. Vous pouvez donc ignorer les anciens niveaux de fonctionnalités et les limitations associées.

Gardez également à l’esprit qu’avec Direct3D 12, vous devez énumérer explicitement les informations sur les appareils à l’aide d’interfaces DXGI. Dans Direct3D 11, vous pouvez remonter à l’appareil DXGI à partir de l’appareil Direct3D, ce qui n’est pas pris en charge pour Direct3D 12.

La création d’un périphérique logiciel WARP sur Direct3D 12 s’effectue en fournissant un adaptateur explicite obtenu à partir d’IDXGIFactory4::EnumWarpAdapter. L’appareil WARP pour Direct3D 12 est disponible uniquement sur les systèmes avec la fonctionnalité facultative Graphics Tools activée.

Notes

Il n’existe aucun équivalent à D3D11CreateDeviceAndSwapChain. Même avec Direct3D 11, nous déconseillons l’utilisation de cette fonction, car il est souvent préférable de créer l’appareil et la chaîne d’échange dans des étapes distinctes.

Ressources validées

Les objets créés avec les interfaces suivantes dans Direct3D 11 se traduisent par ce que l’on appelle des « ressources validées » dans Direct3D 12. Une ressource validée est une ressource qui a un espace d’adressage virtuel et des pages physiques associées. Il s’agit d’un concept du modèle de mémoire Microsoft Windows Device Driver 2 (WDD2), sur lequel Direct3D 12 est basé.

Ressources Direct3D 11 :

Dans Direct3D 12, elles sont toutes représentées par ID3D12Resource et ID3D12Device::CreateCommittedResource.

Ressources réservées

Les ressources réservées sont des ressources où seul l’espace d’adressage virtuel a été alloué, la mémoire physique n’est pas allouée tant qu’il n’y a pas d’appel à ID3D12Device::CreateHeap. Il s’agit essentiellement du même concept que les ressources en mosaïques dans Direct3D 11.

Les indicateurs (D3D11_RESOURCE_MISC_FLAG) utilisés dans Direct3D 11 pour configurer des ressources en mosaïque, puis les mapper à la mémoire physique.

  • D3D11_RESOURCE_MISC_TILED
  • D3D11_RESOURCE_MISC_TILE_POOL

Chargement de données

Dans Direct3D 11, il y a l’apparition d’un seul chronologie (les appels suivant une séquence, comme les données initialisées avec D3D11_SUBRESOURCE_DATA, puis un appel à ID3D11DeviceContext::UpdateSubresource, puis un appel à ID3D11DeviceContext::Map). Le nombre de copies créées des données n’est pas évident pour un développeur Direct3D 11.

Dans Direct3D 12, il existe deux chronologies, la chronologie GPU (configurée par les appels à CopyTextureRegion et CopyBufferRegion à partir de la mémoire mappable) et la chronologie processeur (déterminée par les appels à Map). Des fonctions d’assistance sont fournies (dans le fichier d3dx12.h) appelées Updatesubresources qui utilisent un chronologie partagé. Il existe plusieurs variantes de cette fonction d’assistance, une qui utilise ID3D12Device::GetCopyableFootprints, une autre qui utilise un mécanisme d’allocation de tas et une autre qui utilise un mécanisme d’allocation de pile. Ces fonctions d’assistance copient les ressources vers le GPU et le processeur, via une zone intermédiaire de mémoire intermédiaire.

En règle générale, le GPU et le processeur ont chacun leur propre copie d’une ressource liée à leur propre chronologie. L’approche de chronologie partagée conserve également deux copies.

Nuanceurs et objets de nuanceur

Dans Direct3D 11, il y a beaucoup de création d’objets de nuanceur et d’état, et la définition de l’état de ces objets, à l’aide des méthodes de création ID3D11Device et des méthodes set ID3D11DeviceContext . En règle générale, un grand nombre d’appels sont effectués à ces méthodes, qui sont ensuite combinées au moment du dessin par le pilote pour définir l’état correct du pipeline.

Dans Direct3D 12, ce paramètre d’état de pipeline a été combiné en un seul objet (CreateComputePipelineState pour un moteur de calcul et CreateGraphicsPipelineState pour un moteur graphique), qui est ensuite attaché à une liste de commandes avant l’appel de dessin avec un appel à SetPipelineState.

Ces appels remplacent tous les appels individuels pour définir les nuanceurs, la disposition d’entrée, l’état de fusion, l’état du rastériseur, l’état du gabarit de profondeur, et ainsi de suite, dans Direct3D 11

  • Méthodes de l’appareil 11 : CreateInputLayout, CreateXShader, CreateDepthStencilStateet CreateRasterizerState.
  • Méthodes device Context 11 : IASetInputLayout, xxSetShader, OMSetBlendState, OMSetDepthStencilStateet RSSetState.

Bien que Direct3D 12 puisse prendre en charge des objets blob de nuanceurs compilés plus anciens, les nuanceurs doivent être générés à l’aide du modèle nuanceur 5.1 avec les API FXC/D3DCompile, ou à l’aide du nuanceur modèle 6 à l’aide du compilateur DXIL DXC. Vous devez valider la prise en charge du modèle nuanceur 6 avec CheckFeatureSupport et D3D12_FEATURE_SHADER_MODEL.

Envoi du travail au GPU

Dans Direct3D 11, il y a peu de contrôle sur la façon dont le travail est envoyé, il est en grande partie géré par le pilote, bien qu’un certain contrôle soit activé via les appels ID3D11DeviceContext::Flush et IDXGISwapChain1::P resent1 .

Dans Direct3D 12, la soumission de travail est très explicite et contrôlée par l’application. La construction principale pour l’envoi du travail est l’ID3D12GraphicsCommandList, qui est utilisé pour enregistrer toutes les commandes d’applications (et est assez similaire dans son concept au contexte différé ID3D11). Le magasin de stockage d’une liste de commandes est fourni par ID3D12CommandAllocator, qui permet à l’application de gérer l’utilisation de la mémoire de la liste de commandes en exposant réellement la mémoire que le pilote Direct3D 12 va utiliser pour stocker la liste de commandes.

Enfin, id3D12CommandQueue est une file d’attente premier sorti premier entrant, qui stocke l’ordre correct des listes de commandes à soumettre au GPU. Ce n’est que lorsqu’une liste de commandes a terminé l’exécution sur le GPU que la liste de commandes suivante de la file d’attente est envoyée par le pilote.

Dans Direct3D 11, il n’existe aucun concept explicite de file d’attente de commandes. Dans la configuration courante de Direct3D 12, la liste de commandes D3D12_COMMAND_LIST_TYPE_DIRECT actuellement ouverte pour le frame actuel peut être considérée comme analogue au contexte immédiat Direct3D 11. Cela fournit un grand nombre des mêmes fonctions.

D3D11DeviceContext ID3D12GraphicsCommand List
ClearDepthStencilView ClearDepthStencilView
ClearRenderTargetView ClearRenderTargetView
ClearUnorderedAccess* ClearUnorderedAccess*
Draw, DrawInstanced DrawInstanced
DrawIndexed, DrawIndexedInstanced DrawIndexedInstanced
Dispatch Dispatch
IASetInputLayout, xxSetShader, etc. SetPipelineState
OMSetBlendState OMSetBlendFactor
OMSetDepthStencilState OMSetStencilRef
OMSetRenderTargets OMSetRenderTargets
RSSetViewports RSSetViewports
RSSetScissorRects RSSetScissorRects
IASetPrimitiveTopology IASetPrimitiveTopology
IASetVertexBuffers IASetVertexBuffers
IASetIndexBuffer IASetIndexBuffer
ResolveSubresource ResolveSubresource
CopySubresourceRegion CopyBufferRegion
UpdateSubresource CopyTextureRegion
CopyResource CopyResource

Notes

Une liste de commandes créée avec D3D12_COMMAND_LIST_TYPE_BUNDLE correspond à un contexte différé. Direct3D 12 prend également en charge l’accès simultané à certaines fonctionnalités d’un contexte immédiat au rendu via D3D12_COMMAND_LIST_TYPE_COPY et D3D12_COMMAND_LIST_TYPE_COMPUTE types de liste de commandes.

Synchronisation processeur/GPU

Dans Direct3D 11, la synchronisation processeur/GPU était en grande partie automatique, et l’application n’avait pas besoin de maintenir la status de la mémoire physique.

Dans Direct3D 12, l’application doit gérer explicitement les deux chronologies (PROCESSEUR et GPU). Cela nécessite que les informations soient conservées par l’application sur les ressources requises par le GPU et pendant combien de temps. Cela signifie également que l’application est chargée de s’assurer que le contenu des ressources (ressources validées, tas, allocateurs de commandes, par exemple) ne change pas tant que le GPU n’a pas fini de les utiliser.

L’objet main pour synchroniser les chronologies est l’objet ID3D12Fence. Le fonctionnement des clôtures est assez simple, ils permettent au GPU de signaler quand il a terminé une tâche. Le GPU et le processeur peuvent tous les deux signaler, et peuvent tous deux attendre sur des clôtures.

En règle générale, lors de l’envoi d’une liste de commandes pour exécution, un signal de clôture est transmis par le GPU à l’achèvement (lorsqu’il a terminé de lire les données), ce qui permet au processeur de réutiliser ou de détruire les ressources.

Dans Direct3D 11, l’indicateur ID3D11DeviceContext::Map D3D11_MAP_WRITE_DISCARD essentiellement traité chaque ressource comme une quantité infinie de mémoire dans laquelle l’application pouvait écrire (processus appelé « renommage »). Dans Direct3D 12, le processus est explicite : une mémoire supplémentaire doit être allouée et des clôtures doivent être utilisées pour synchroniser les opérations. Les mémoires tampons en anneau (composées de mémoires tampons volumineuses) peuvent être une bonne technique pour cela. Reportez-vous au scénario de mémoire tampon en anneau dans Gestion des ressources basée sur les clôtures.

utilisation d’une mémoire tampon en anneau

Liaison de ressources

Les vues dans Direct3D 11 (affichages de ressources de nuanceur, affichage cible de rendu, etc.) ont été largement remplacées dans Direct3D 12 par le concept de descripteur. Les méthodes de création existent toujours dans Direct3D 12 (telles que CreateShaderResourceView et CreateRenderTargetView), qui sont appelées après la création du tas de descripteur, pour écrire les données dans le tas. La liaison dans Direct3D 12 est désormais gérée par les handles de descripteurs décrits dans une signature racine et envoyée à l’aide des méthodes SetGraphicsRootDescriptorTable ou SetComputeRootDescriptorTable .

Les mappages de détails des signatures racines entre le numéro d’emplacement de signature racine et les tables de descripteur, où la table de descripteur peut contenir des références aux ressources disponibles pour les nuanceurs de vertex, les nuanceurs de pixels et les autres nuanceurs, tels que les mémoires tampons constantes, les vues de ressources du nuanceur et les échantillonneurs. Cette flexibilité déconnecte l’espace d’enregistrement HLSL de l’espace de liaison d’API dans Direct3D 12, contrairement à Direct3D 11 où il existe un mappage un-à-un entre ces derniers.

L’une des implications de ce système est que l’application est responsable du renommage des tables de descripteurs, ce qui permet aux développeurs de comprendre le coût de performances de la modification d’un seul descripteur par appel de tirage.

Une nouvelle fonctionnalité de Direct3D 12 est qu’une application peut contrôler les descripteurs partagés entre les différentes étapes du nuanceur. Dans Direct3D 11, les ressources telles que les UAV sont partagées entre toutes les étapes du nuanceur. En permettant aux descripteurs d’être désactivés pour certaines étapes du nuanceur, les registres utilisés par les descripteurs qui ont été désactivés peuvent être utilisés par les descripteurs activés pour une étape de nuanceur particulière.

Le tableau suivant montre un exemple de signature racine.

Emplacement de paramètre racine Entrée de table de descripteur
0 Plage de descripteurs VS b0-b13
1 Plage de descripteur VS t0-t127
2 Plage de descripteurs VS s0-s16
3 Plage de descripteurs PS b0-b13
...
14 Plage de descripteurs DS s0-16
15 Plage de descripteurs partagés u0-u63

 

État de la ressource

Dans Direct3D 11, l’état des ressources n’est pas géré par l’application, mais par le pilote.

Dans Direct3D 12, la gestion de l’état des ressources devient la responsabilité de l’application, pour activer le parallélisme complet dans l’enregistrement des listes de commandes : l’application doit gérer les chronologies d’enregistrement des listes de commandes (qui peuvent être effectuées en parallèle) et les chronologies d’exécution qui doivent être séquentielles.

Une transition d’état de ressource est gérée par la méthode ResourceBarrier . Principalement, l’application doit informer le pilote lorsque l’utilisation des ressources change. Par exemple, si une ressource est utilisée comme cible de rendu, puis qu’elle doit être utilisée comme entrée d’un nuanceur de vertex lors de l’appel de dessin suivant, cela peut nécessiter un court décrochage dans l’opération GPU pour terminer l’opération de cible de rendu avant de gérer le nuanceur de vertex.

Ce système permet la synchronisation de grains fins (les décrochages GPU) du pipeline graphique, ainsi que les vidages de cache et éventuellement certaines modifications de disposition de la mémoire (telles que le rendu de la vue cible vers la décompression de la vue de gabarit de profondeur).

C’est ce qu’on appelle un obstacle de transition. Il existe d’autres types de barrières. Dans Direct3D 11, ID3D11DeviceContext2::TiledResourceBarrier a activé la même mémoire physique à utiliser par deux ressources en mosaïques différentes. Dans Direct3D 12, cela est appelé « barrière d’aliasing ». Les barrières d’alias peuvent être utilisées pour les ressources en mosaïque et placées dans Direct3D 12. En outre, il y a la barrière UAV. Dans Direct3D 11, toutes les opérations de distribution et de dessin par UAV doivent être sérialisées, même si ces opérations peuvent être pipelineées ou fonctionner en parallèle. Pour Direct3D 12, cette restriction est supprimée par l’ajout d’une barrière UAV. Une barrière UAV garantit que les opérations UAV sont séquentielles. Par conséquent, si une deuxième opération nécessite que la première soit terminée, la seconde est contrainte d’attendre par l’ajout de la barrière. L’opération par défaut pour les UAV est simplement que les opérations se poursuivent aussi rapidement que possible.

De toute évidence, il y a des gains de performances si une charge de travail peut être parallélisée.

Swapchains

La chaîne d’échange DXGI est la base des chaînes d’échange dans Direct3D 11 et 12. Il existe quelques différences mineures, dans Direct3D 11, les trois types de chaîne d’échange sont SÉQUENTIELLE, DISCARD et FLIP_SEQUENTIAL. Pour Direct3D 12, il n’existe que deux types : FLIP_SEQUENTIAL et FLIP_DISCARD. Comme indiqué ci-dessus, vous devez créer explicitement votre chaîne d’échange via IDXGIFactory4 ou une version ultérieure, et utiliser la même interface pour toute énumération d’adaptateur.

Dans Direct3D 11, il existe une rotation automatique du backbuffer : une seule vue cible de rendu est nécessaire pour la mémoire tampon arrière 0. Dans Direct3D 12, la rotation de la mémoire tampon est explicite, il doit y avoir une vue cible de rendu pour chaque mémoire tampon d’arrière-mémoire. Utilisez la méthode IDXGISwapChain3::GetCurrentBackBufferIndex pour sélectionner celle vers laquelle effectuer le rendu. Là encore, cette flexibilité supplémentaire permet une plus grande parallélisation.

Notes

Bien qu’il existe de nombreuses façons de configurer votre application, les applications ont généralement un ID3D12CommandAllocator par mémoire tampon de chaîne d’échange. Cela permet à l’application de continuer à générer un ensemble de commandes pour la trame suivante pendant que le GPU restitue la précédente.

Rendu de fonction fixe

Dans Direct3D 11, il existait quelques méthodes qui simplifient diverses opérations de niveau supérieur, telles que GenerateMips (création de chaînes mip complètes) et DrawAuto (utilisation de la sortie de flux comme entrée de nuanceur sans autre entrée de l’application). Ces méthodes ne sont pas disponibles dans Direct3D 12. L’application doit gérer ces opérations en créant des nuanceurs pour les exécuter.

Cotes et fins

Le tableau suivant présente un certain nombre de fonctionnalités similaires entre Direct3D 11 et 12, mais qui ne sont pas identiques.

Direct3D 11 Direct3D 12
ID3D11Query ID3D12QueryHeap permet de regrouper les requêtes, ce qui réduit les coûts.
ID3D11Predicate La prédication est désormais activée en ayant des données dans une mémoire tampon entièrement transparente. L’objet Direct3D 11 ID3D11Predicate est remplacé par ID3D12Resource::Map, qui doit suivre un appel à ResolveQueryData et une opération de synchronisation GPU utilisant une clôture pour attendre que les données soient prêtes. Reportez-vous à Prédication.
Compteur masqué UAV/SO L’application est responsable de l’allocation et de la gestion des compteurs SO/UAV. Reportez-vous à Compteurs de sortie de flux et Compteurs UAV.
MinLOD dynamique de la ressource (niveau de détail minium) Cela a été déplacé vers le descripteur SRV statique MinLOD.
Draw*Indirect/DispatchIndirect Les méthodes indirectes de dessin sont toutes fusionnées dans la seule méthode ExecuteIndirect .
Les formats DepthStencil sont entrelacés Les formats DepthStencil sont planaires. Par exemple, un format de 24 bits de profondeur, 8 bits de gabarit sont stockés au format 24/8/24/8... etc dans Direct3D 11, mais comme 24/24/24... suivi du 8/8/8... dans Direct3D 12. Notez que chaque plan est sa propre sous-ressource dans D3D12 ( reportez-vous à Sous-ressources).
ResizeTilePool Les ressources réservées peuvent être mappées à plusieurs tas. Lorsqu’un pool de vignettes aurait été développé dans D3D11, un tas supplémentaire peut être alloué dans D3D12 à la place.

 

Tutoriels vidéo de l’apprentissage avancé DirectX : Guide de portage directX 11 vers DirectX 12

Comprendre Direct3D 12

Utilisation de Direct3D 11, Direct3D 10 et Direct2D