Portage de Direct3D 11 sur Direct3D 12
Cette section fournit des conseils sur le portage d’un moteur graphique Direct3D 11 personnalisé vers Direct3D 12.
- Création d’appareils
- Ressources validées
- Ressources réservées
- Chargement de données
- Nuanceurs et objets de nuanceur
- Envoi d’un travail au GPU
- Synchronisation processeur/GPU
- Liaison de ressources
- État de la ressource
- Chains d’échange
- Rendu de fonction fixe
- Cotes et extrémités
- Rubriques connexes
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, ce qui vous permet d’ignorer les niveaux de fonctionnalités plus anciens et les limitations associées.
Gardez également à l’esprit que, avec Direct3D 12, vous devez énumérer explicitement les informations d’appareil à l’aide d’interfaces DXGI. Dans Direct3D 11, vous pouvez revenir à l’appareil DXGI à partir de l’appareil Direct3D, et cela n’est pas pris en charge pour Direct3D 12.
La création d’un périphérique logiciel WARP sur Direct3D 12 est effectuée 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.
Remarque
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 en étapes distinctes.
Ressources engagées
Les objets créés avec les interfaces suivantes dans Direct3D 11 se traduisent par ce qui est appelé « ressources validées » dans Direct3D 12. Une ressource validée est une ressource qui a à la fois 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 :
- ID3D11Resource
- ID3D11Buffer et ID3D11Device ::CreateBuffer
- ID3D11Texture1D et ID3D11Device :CreateTexture1D
- ID3D11Texture2D et ID3D11Device ::CreateTexture2D
- ID3D11Texture3D et ID3D11Device ::CreateTexture3D
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ù seuls 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.
Indicateurs (D3D11_RESOURCE_MISC_FLAG) utilisés dans Direct3D 11 pour configurer des ressources en mosaïques, puis les mapper à la mémoire physique.
- D3D11_RESOURCE_MISC_TILED
- D3D11_RESOURCE_MISC_TILE_POOL
Chargement de données
Dans Direct3D 11, il existe l’apparence d’une chronologie unique (appels suivant une séquence, telles que les données initialisées avec D3D11_SUBRESOURCE_DATA, puis un appel est effectué à 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 du processeur (déterminée par les appels à Map). Les fonctions d’assistance sont fournies (dans le fichier d3dx12.h) appelées Updatesubresources qui utilisent une chronologie partagée. 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 l’UC ont chacun leur propre copie d’une ressource liée à leur propre chronologie. L’approche de chronologie partagée conserve de même deux copies.
Nuanceurs et objets de nuanceur
Dans Direct3D 11, il existe 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 des nuanceurs, une disposition d’entrée, un état de fusion, un état de rastériseur, un état de gabarit de profondeur, et ainsi de suite, dans Direct3D 11
- Méthodes d’appareil 11 :
CreateInputLayout
, ,CreateXShader
CreateDepthStencilState
, etCreateRasterizerState
. - Méthodes device Context 11 :
IASetInputLayout
, ,xxSetShader
OMSetBlendState
,OMSetDepthStencilState
, etRSSetState
.
Bien que Direct3D 12 puisse prendre en charge les objets blob de nuanceurs compilés plus anciens, les nuanceurs doivent être générés à l’aide du modèle de nuanceur 5.1 avec les API FXC/D3DCompile, ou à l’aide du modèle de nuanceur 6 à l’aide du compilateur DXIL DXC. Vous devez valider la prise en charge de Shader Model 6 avec CheckFeatureSupport et D3D12_FEATURE_SHADER_MODEL.
Envoi d’un travail au GPU
Dans Direct3D 11, il existe peu de contrôle sur la façon dont le travail est envoyé, mais il est largement géré par le pilote, bien que certains contrôles soient activés via les appels ID3D11DeviceContext ::Flush et IDXGISwapChain1 ::P resent1.
Dans la soumission de travail Direct3D 12, elle est très explicite et contrôlée par l’application. La construction principale pour l’envoi de travail est ID3D12GraphicsCommandList, qui est utilisée pour enregistrer toutes les commandes d’applications (et est assez similaire au concept du contexte différé ID3D11). Le magasin de stockage d’une liste de commandes est fourni par l’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, l’ID3D12CommandQueue est une file d’attente de première entrée sortante qui stocke l’ordre correct des listes de commandes à soumettre au GPU. Une seule fois qu’une liste de commandes a terminé l’exécution sur le GPU, la liste de commandes suivante de la file d’attente est soumise par le pilote.
Dans Direct3D 11, il n’existe aucun concept explicite d’une file d’attente de commandes. Dans la configuration courante de Direct3D 12, la liste de commandes D3D12_COMMAND_LIST_TYPE_DIRECT actuellement ouverte pour l’image actuelle peut être considérée comme analogue au contexte immédiat Direct3D 11. Cela fournit une grande partie des mêmes fonctions.
D3D11DeviceContext | ID3D12GraphicsCommand List |
---|---|
ClearDepthStencilView | ClearDepthStencilView |
ClearRenderTargetView | ClearRenderTargetView |
ClearUnorderedAccess* | ClearUnorderedAccess* |
Draw, DrawInstanced | DrawInstanced |
DrawIndexed, DrawIndexedInstanced | DrawIndexedInstanced |
Expédition | Expédition |
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 |
Remarque
Une liste de commandes créée avec D3D12_COMMAND_LIST_TYPE_BUNDLE est simliar dans un contexte différé. Direct3D 12 prend également en charge la possibilité d’accéder à certaines fonctionnalités d’un contexte immédiat simultané au rendu via D3D12_COMMAND_LIST_TYPE_COPY et D3D12_COMMAND_LIST_TYPE_COMPUTE types de liste de commandes.
Synchronisation processeur/GPU
Dans la synchronisation processeur/GPU Direct3D 11 était en grande partie automatique et il n’était pas nécessaire que l’application conserve l’état 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 garantir le contenu des ressources (ressources validées, tas, allocateurs de commandes, par exemple) ne changent pas tant que le GPU n’a pas terminé de les utiliser.
L’objet principal pour la synchronisation des chronologies est l’objet ID3D12Fence . Le fonctionnement des clôtures est assez simple, ils permettent au GPU de signaler lorsqu’il a terminé une tâche. Le GPU et l’UC peuvent à la fois signaler et attendre les deux sur des clôtures.
En règle générale, l’approche consiste à envoyer une liste de commandes pour l’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 peut écrire (un processus appelé « renommage »). Dans Direct3D 12, le processus est explicite : la mémoire supplémentaire doit être allouée et les 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 la gestion des ressources basée sur la clôture.
Liaison de ressources
Les vues dans Direct3D 11 (vues de ressources de nuanceur, affichages cibles de rendu, et ainsi de suite) ont été remplacées dans Direct3D 12 par le concept de descripteur. Les méthodes de création existent toujours dans Direct3D 12 (par exemple, CreateShaderResourceView et CreateRenderTargetView), 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 des handles de descripteur 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 de nuanceur et les échantillonneurs. Cette flexibilité déconnecte l’espace d’inscription HLSL de l’espace de liaison d’API dans Direct3D 12, contrairement à Direct3D 11 où il existe un mappage d’un à un entre ceux-ci.
L’une des implications de ce système est que l’application est responsable du renommage des tables de descripteur, ce qui permet aux développeurs de comprendre le coût des 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 quels descripteurs sont partagés entre les étapes du nuanceur. Dans les ressources Direct3D 11, telles que les UAV, sont partagées entre toutes les étapes du nuanceur. En permettant aux descripteurs d’être désactivés pour certaines phases de nuanceur, les registres utilisés par les descripteurs désactivés sont disponibles pour être utilisés par les descripteurs activés pour une étape de nuanceur particulière.
Le tableau suivant présente un exemple de signature racine.
Emplacement de paramètre racine | Entrée de table de descripteur |
---|---|
0 | Plage de descripteur VS b0-b13 |
1 | Plage de descripteur VS t0-t127 |
2 | Plage de descripteur VS s0-s16 |
3 | Plage de descripteur PS b0-b13 |
... | |
14 | Plage de descripteur DS s0-16 |
15 | Plage de descripteur partagée u0-u63 |
État de la ressource
Dans l’état des ressources Direct3D 11, il n’est pas conservé 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 total 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 dans un nuanceur de vertex lors de l’appel de dessin suivant, cela peut nécessiter un court blocage 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 fine des grains (les blocages gpu) du pipeline graphique, ainsi que les vidages de cache et éventuellement certaines modifications de disposition de la mémoire (par exemple, afficher la vue cible de rendu en mode gabarit de profondeur en décompression).
C’est ce qu’on appelle une barrière de transition. Il existe d’autres types de barrières, dans Direct3D 11, l’ID3D11DeviceContext2 ::TiledResourceBarrier a activé la même mémoire physique à utiliser par deux ressources en mosaïques différentes. Dans Direct3D 12, il s’agit d’une « barrière d’alias ». Les barrières d’alias peuvent être utilisées pour les ressources en mosaïques et placées dans Direct3D 12. En outre, il y a la barrière de l’UAV. Dans Direct3D 11, toutes les opérations de distribution et de dessin de l’UAV doivent être sérialisées, même si ces opérations peuvent être pipelinedé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 exige que la première se termine, la seconde sera forcée d’attendre par l’ajout de la barrière. L’opération par défaut pour les UAV est simplement que les opérations vont se poursuivre aussi rapidement que possible.
Il existe clairement des gains de performances si une charge de travail peut être parallélisée.
Chains d’échange
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ÉQUENTIELS, 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 version ultérieure, et utiliser la même interface pour n’importe quelle énumération d’adaptateur.
Dans Direct3D 11, il existe une rotation automatique des backbuffers : une seule vue cible de rendu est nécessaire pour la mémoire tampon de retour 0. Dans la rotation de la mémoire tampon Direct3D 12 est explicite, il doit y avoir une vue cible de rendu pour chaque mémoire tampon arrière. Utilisez la méthode IDXGISwapChain3 ::GetCurrentBackBufferIndex pour sélectionner celle à laquelle effectuer le rendu. Là encore, cette flexibilité supplémentaire permet une plus grande parallélisation.
Remarque
Bien qu’il existe de nombreuses façons de configurer votre application, les applications ont généralement un tampon ID3D12CommandAllocator par chaîne d’échange. Cela permet à l’application de continuer à créer un ensemble de commandes pour l’image suivante pendant que le GPU restitue l’ancien.
Rendu de fonction fixe
Dans Direct3D 11, quelques méthodes ont simplifié différentes opérations de niveau supérieur, telles que GenerateMips (création de chaînes mip complètes) et DrawAuto (à l’aide de la sortie de flux en tant qu’entrée de nuanceur sans entrée supplémentaire 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 effectuer.
Cotes et extrémités
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 aux requêtes d’être regroupées, ce qui réduit le coût. |
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 à l’aide d’une clôture pour attendre que les données soient prêtes. Reportez-vous à La prédication. |
Compteur masqué UAV/SO | L’application est responsable de l’allocation et de la gestion des compteurs SO/UAV. Reportez-vous aux compteurs de sortie de flux et aux compteurs UAV. |
MinLOD dynamique de ressource (minium level of detail) | Cela a été déplacé vers le descripteur statique SRV MinLOD. |
Draw*Indirect/DispatchIndirect | Les méthodes indirectes de dessin sont toutes fusionnées dans la 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 aux sous-ressources). |
ResizeTilePool | Les ressources réservées peuvent être mappées à plusieurs tas. Lorsqu’un pool de mosaïques aurait été agrandi en D3D11, un tas supplémentaire peut être alloué dans D3D12 à la place. |