Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans DirectML, la liaison fait référence à l'attachement des ressources au pipeline afin que le GPU puisse les utiliser pendant l'initialisation et l'exécution de vos opérateurs d'apprentissage automatique. Ces ressources peuvent être des tenseurs d’entrée et de sortie, par exemple, ainsi que toutes les ressources temporaires ou persistantes dont l’opérateur a besoin.
Cette rubrique traite des détails conceptuels et procéduraux de la liaison. Nous vous recommandons également de lire entièrement la documentation des API que vous appelez, y compris les paramètres et les remarques.
Idées importantes dans le reliure
La liste des étapes ci-dessous contient une description générale des tâches liées à l'assemblage. Vous devez suivre ces étapes chaque fois que vous exécutez un dispatchable—un initialiseur d'opérateur ou un opérateur compilé. Ces étapes présentent les idées, structures et méthodes importantes impliquées dans la liaison DirectML.
Les sections suivantes de cette rubrique approfondissent et expliquent ces tâches de liaison plus en détail, avec des extraits illustrant l'exemple de code d'application DirectML minimal.
- Appelez IDMLDispatchable ::GetBindingProperties sur le répartiteur pour déterminer le nombre de descripteurs dont il a besoin, ainsi que ses besoins en ressources temporaires/persistantes.
- Créez un tas de descripteur Direct3D 12 suffisamment grand pour les descripteurs et liez-le au pipeline.
- Appelez IDMLDevice ::CreateBindingTable pour créer une table de liaison DirectML pour représenter les ressources liées au pipeline. Utilisez la structure DML_BINDING_TABLE_DESC pour décrire votre table de liaison, y compris le sous-ensemble des descripteurs sur lequel il pointe dans le tas de descripteurs.
- Créez des ressources temporaires/persistantes en tant que ressources de mémoire tampon Direct3D 12, décrivez-les avec des structures DML_BUFFER_BINDING et DML_BINDING_DESC , puis ajoutez-les à la table de liaison.
- Si l'opérateur dispatchable est un opérateur compilé, créez une mémoire tampon pour les éléments tensoriels en tant que ressource de mémoire tampon Direct3D 12. Remplissez-le ou chargez-le, décrivez-le avec les structures DML_BUFFER_BINDING et DML_BINDING_DESC, puis ajoutez-le à la table de liaison.
- Transmettez votre table de liaison en tant que paramètre lorsque vous appelez IDMLCommandRecorder ::RecordDispatch.
Récupérer les propriétés de liaison d’un répartitable
La structure DML_BINDING_PROPERTIES décrit les besoins de liaison d'un opérateur déclenchable (initialiseur d'opérateur ou opérateur compilé). Ces propriétés liées à la liaison incluent le nombre de descripteurs que vous devez lier à l'unité d'exécution, ainsi que la taille en octets des ressources temporaires et/ou persistantes nécessaires.
Remarque
Même pour plusieurs opérateurs du même type, ne faites pas d’hypothèses sur ces opérateurs ayant les mêmes conditions de liaison. Interrogez les propriétés de liaison pour chaque initialiseur et opérateur que vous créez.
Appelez IDMLDispatchable ::GetBindingProperties pour récupérer un DML_BINDING_PROPERTIES.
winrt::com_ptr<::IDMLCompiledOperator> dmlCompiledOperator;
// Code to create and compile a DirectML operator goes here.
DML_BINDING_PROPERTIES executeDmlBindingProperties{
dmlCompiledOperator->GetBindingProperties()
};
winrt::com_ptr<::IDMLOperatorInitializer> dmlOperatorInitializer;
// Code to create a DirectML operator initializer goes here.
DML_BINDING_PROPERTIES initializeDmlBindingProperties{
dmlOperatorInitializer->GetBindingProperties()
};
UINT descriptorCount = ...
La descriptorCount valeur que vous récupérez ici détermine la taille (minimale) du tas de descripteur et de la table de liaison que vous créez dans les deux étapes suivantes.
DML_BINDING_PROPERTIES contient également un TemporaryResourceSize membre, qui est la taille minimale en octets de la ressource temporaire qui doit être liée à la table de liaison pour cet objet répartitable. La valeur zéro signifie qu’une ressource temporaire n’est pas nécessaire.
Et un PersistentResourceSize élément, qui est la taille minimale en octets de la ressource persistante qui doit être liée dans la table de liaison pour cet objet exécutable. La valeur zéro signifie qu’une ressource persistante n’est pas nécessaire. Une ressource persistante, si nécessaire, doit être fournie lors de l’initialisation d’un opérateur compilé (où elle est liée en tant que sortie de l’initialiseur d’opérateur) ainsi qu’au cours de l’exécution. Plus loin dans cette rubrique, vous trouverez plus d’informations. Seuls les opérateurs compilés ont des ressources persistantes. Les initialiseurs d’opérateurs retournent toujours une valeur de 0 pour ce membre.
Si vous appelez IDMLDispatchable ::GetBindingProperties sur un initialiseur d’opérateur avant et après un appel à IDMLOperatorInitializer ::Reset, les deux ensembles de propriétés de liaison récupérées ne sont pas garantis comme identiques.
Décrire, créer et lier un tas de descripteurs
En termes de descripteurs, votre responsabilité commence et se termine par la pile de descripteurs elle-même. DirectML lui-même s’occupe de la création et de la gestion des descripteurs à l’intérieur du tas que vous fournissez.
Utilisez donc une structure D3D12_DESCRIPTOR_HEAP_DESC pour décrire un tas suffisamment grand pour le nombre de descripteurs nécessaires au dispatchable. Ensuite, créez-le avec ID3D12Device ::CreateDescriptorHeap. Enfin, appelez ID3D12GraphicsCommandList ::SetDescriptorHeaps pour lier votre tas de descripteur au pipeline.
winrt::com_ptr<::ID3D12DescriptorHeap> d3D12DescriptorHeap;
D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDescription{};
descriptorHeapDescription.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
descriptorHeapDescription.NumDescriptors = descriptorCount;
descriptorHeapDescription.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
winrt::check_hresult(
d3D12Device->CreateDescriptorHeap(
&descriptorHeapDescription,
_uuidof(d3D12DescriptorHeap),
d3D12DescriptorHeap.put_void()
)
);
std::array<ID3D12DescriptorHeap*, 1> d3D12DescriptorHeaps{ d3D12DescriptorHeap.get() };
d3D12GraphicsCommandList->SetDescriptorHeaps(
static_cast<UINT>(d3D12DescriptorHeaps.size()),
d3D12DescriptorHeaps.data()
);
Décrire et créer une table de liaison
Une table de liaison DirectML représente les ressources que vous associez au pipeline pour qu’un dispatchable puisse les utiliser. Ces ressources peuvent être des tenseurs d’entrée et de sortie (ou d’autres paramètres) pour un opérateur, ou elles peuvent être différentes ressources persistantes et temporaires avec lesquelles un processus dispatchable peut fonctionner.
Utilisez la structure DML_BINDING_TABLE_DESC pour décrire votre table de liaison, y compris l'élément dispatchable pour lequel la table de liaison représentera les liaisons, et l'ensemble de descripteurs (à partir du tas de descripteurs que vous venez de créer) auquel vous souhaitez que la table de liaison se réfère (et dans lequel DirectML peut écrire des descripteurs). La descriptorCount valeur (une des propriétés de liaison que nous avons récupérées lors de la première étape) nous indique la taille minimale, dans les descripteurs, de la table de liaison requise pour l’objet répartitable. Ici, nous utilisons cette valeur pour indiquer le nombre maximal de descripteurs que DirectML est autorisé à écrire dans notre espace mémoire, depuis le début des handles de descripteur CPU et GPU fournis.
Appelez ensuite IDMLDevice ::CreateBindingTable pour créer la table de liaison DirectML. Dans les étapes ultérieures, une fois que nous avons créé d’autres ressources pour le répartiteur, nous allons ajouter ces ressources à la table de liaison.
Au lieu de passer un DML_BINDING_TABLE_DESC à cet appel, vous pouvez passer nullptr, ce qui indique une table de liaison vide.
DML_BINDING_TABLE_DESC dmlBindingTableDesc{};
dmlBindingTableDesc.Dispatchable = dmlOperatorInitializer.get();
dmlBindingTableDesc.CPUDescriptorHandle = d3D12DescriptorHeap->GetCPUDescriptorHandleForHeapStart();
dmlBindingTableDesc.GPUDescriptorHandle = d3D12DescriptorHeap->GetGPUDescriptorHandleForHeapStart();
dmlBindingTableDesc.SizeInDescriptors = descriptorCount;
winrt::com_ptr<::IDMLBindingTable> dmlBindingTable;
winrt::check_hresult(
dmlDevice->CreateBindingTable(
&dmlBindingTableDesc,
__uuidof(dmlBindingTable),
dmlBindingTable.put_void()
)
);
L’ordre dans lequel DirectML écrit des descripteurs dans le tas n’est pas spécifié. Par conséquent, votre application doit s’occuper de ne pas remplacer les descripteurs encapsulés par la table de liaison. Les handles de descripteurs CPU et GPU fournis peuvent provenir de différents segments de mémoire, mais il incombe ensuite à votre application de s'assurer que toute la plage de descripteurs référencée par le handle de descripteur CPU est copiée dans la plage référencée par le handle de descripteur GPU avant l'exécution en utilisant cette table de correspondance. Le tas de descripteur à partir duquel les handles sont fournis doit avoir le type D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV. En outre, le tas référencé par GPUDescriptorHandle doit être un tas de descripteurs visible par le shader.
Vous pouvez réinitialiser une table de liaison pour supprimer toutes les ressources que vous avez ajoutées à celle-ci, tout en modifiant en même temps toute propriété que vous définissez sur son DML_BINDING_TABLE_DESC initial (pour encapsuler une nouvelle plage de descripteurs ou pour la réutiliser pour une distribution différente). Apportez simplement les modifications à la structure de description et appelez IDMLBindingTable ::Reset.
dmlBindingTableDesc.Dispatchable = pIDMLCompiledOperator.get();
winrt::check_hresult(
pIDMLBindingTable->Reset(
&dmlBindingTableDesc
)
);
Décrire et lier toutes les ressources temporaires/persistantes
La structure DML_BINDING_PROPERTIES que nous avons renseignée lorsque nous avons récupéré les propriétés de liaison de notre élément dispatchable contient la taille en octets de toute ressource temporaire et/ou persistante nécessaire à l'élément. Si l’une de ces tailles n’est pas égale à zéro, créez une ressource de mémoire tampon Direct3D 12 et ajoutez-la à la table de liaison.
Dans l’exemple de code ci-dessous, nous créons une ressource temporaire (temporaryResourceSize octets de taille) pour le dispatcheur. Nous décrivons comment nous souhaitons lier la ressource, puis nous ajoutons cette liaison à la table de liaison.
Comme nous lions une ressource unique de mémoire tampon, nous décrivons notre liaison avec une structure DML_BUFFER_BINDING. Dans cette structure, nous spécifions la ressource de mémoire tampon Direct3D 12 (la ressource doit avoir une dimension D3D12_RESOURCE_DIMENSION_BUFFER), ainsi qu’un décalage et une taille dans la mémoire tampon. Il est également possible de décrire une liaison pour un tableau de mémoires tampons (plutôt que pour une seule mémoire tampon) et la structure DML_BUFFER_ARRAY_BINDING existe à cet effet.
Pour extraire la distinction entre une liaison de mémoire tampon et une liaison de tableau de mémoires tampons, nous utilisons la structure DML_BINDING_DESC . Vous pouvez définir le Type membre du DML_BINDING_DESC sur DML_BINDING_TYPE_BUFFER ou DML_BINDING_TYPE_BUFFER_ARRAY. Vous pouvez ensuite ajuster le membre Desc pour qu'il pointe vers un DML_BUFFER_BINDING ou vers un DML_BUFFER_ARRAY_BINDING, selon Type.
Nous traitons la ressource temporaire dans cet exemple. Nous l’ajoutons donc à la table de liaison avec un appel à IDMLBindingTable ::BindTemporaryResource.
D3D12_HEAP_PROPERTIES defaultHeapProperties{ CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT) };
winrt::com_ptr<::ID3D12Resource> temporaryBuffer;
D3D12_RESOURCE_DESC temporaryBufferDesc{ CD3DX12_RESOURCE_DESC::Buffer(temporaryResourceSize) };
winrt::check_hresult(
d3D12Device->CreateCommittedResource(
&defaultHeapProperties,
D3D12_HEAP_FLAG_NONE,
&temporaryBufferDesc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
__uuidof(temporaryBuffer),
temporaryBuffer.put_void()
)
);
DML_BUFFER_BINDING bufferBinding{ temporaryBuffer.get(), 0, temporaryResourceSize };
DML_BINDING_DESC bindingDesc{ DML_BINDING_TYPE_BUFFER, &bufferBinding };
dmlBindingTable->BindTemporaryResource(&bindingDesc);
Une ressource temporaire (si nécessaire) est une mémoire temporaire utilisée en interne lors de l'exécution de l'opérateur, vous n'avez donc pas besoin de vous préoccuper de son contenu. Vous n’avez pas non plus besoin de le conserver après votre commande à IDMLCommandRecorder::RecordDispatch sur le GPU. Cela signifie que votre application peut libérer ou remplacer la ressource temporaire entre les exécutions de l’opérateur compilé. La plage de mémoire tampon fournie à lier comme ressource temporaire doit avoir son décalage de début aligné sur DML_TEMPORARY_BUFFER_ALIGNMENT. Le type du tas sous-jacent à la mémoire tampon doit être D3D12_HEAP_TYPE_DEFAULT.
Si le répartiteur signale une taille non nulle pour sa ressource persistante de plus longue durée, cependant, la procédure est un peu différente. Vous devez créer une mémoire tampon et décrire une liaison suivant le même modèle que celui indiqué ci-dessus. Mais ajoutez-la à la table de liaison de votre opérateur initialiseur avec un appel à IDMLBindingTable ::BindOutputs, car il s’agit du travail de l’initialiseur d’opérateur pour initialiser la ressource persistante. Ensuite, ajoutez-la à la table de liaisons de votre opérateur compilé en appelant IDMLBindingTable::BindPersistentResource. Consultez l’exemple de code d’application DirectML minimal pour voir ce flux de travail en action. Le contenu et la durée de vie de la ressource persistante doivent être conservés tant que l'opérateur compilé existe. Autrement dit, si un opérateur nécessite une ressource persistante, votre application doit la fournir lors de l’initialisation, puis la fournir à toutes les futures exécutions de l’opérateur sans modifier son contenu. La ressource persistante est généralement utilisée par DirectML pour stocker des tables de recherche ou d’autres données de longue durée calculées lors de l’initialisation d’un opérateur et réutilisées lors des exécutions futures de cet opérateur. La plage de mémoire tampon fournie à lier comme mémoire tampon persistante doit avoir un décalage de début aligné sur DML_PERSISTENT_BUFFER_ALIGNMENT. Le type du tas sous-jacent à la mémoire tampon doit être D3D12_HEAP_TYPE_DEFAULT.
Décrire et lier tous les tenseurs
Si vous traitez d’un opérateur compilé (plutôt qu’avec un initialiseur d’opérateur), vous devez lier des ressources d’entrée et de sortie (pour les tenseurs et d’autres paramètres) à la table de liaison de l’opérateur. Le nombre de liaisons doit correspondre exactement au nombre d’entrées de l’opérateur, y compris les tenseurs facultatifs. Les tenseurs d’entrée et de sortie particuliers et d’autres paramètres qu’un opérateur prend sont documentés dans la rubrique de cet opérateur (par exemple, DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC).
Une ressource de capteur est une mémoire tampon qui contient les valeurs d’élément individuelles du capteur. Vous chargez et lisez de telles mémoires tampons vers/depuis le GPU à l’aide des techniques Direct3D 12 standard (Charger des ressources et lire des données via une mémoire tampon). Consultez l’exemple de code d’application DirectML minimal pour voir ces techniques en action.
Enfin, décrivez vos liaisons de ressources d’entrée et de sortie avec des structures DML_BUFFER_BINDING et DML_BINDING_DESC , puis ajoutez-les à la table de liaison de l’opérateur compilé avec des appels à IDMLBindingTable ::BindInputs et IDMLBindingTable ::BindOutputs. Lorsque vous appelez une méthode IDMLBindingTable::Bind*, DirectML écrit un ou plusieurs descripteurs dans la plage de descripteurs de CPU.
DML_BUFFER_BINDING inputBufferBinding{ inputBuffer.get(), 0, tensorBufferSize };
DML_BINDING_DESC inputBindingDesc{ DML_BINDING_TYPE_BUFFER, &inputBufferBinding };
dmlBindingTable->BindInputs(1, &inputBindingDesc);
DML_BUFFER_BINDING outputBufferBinding{ outputBuffer.get(), 0, tensorBufferSize };
DML_BINDING_DESC outputBindingDesc{ DML_BINDING_TYPE_BUFFER, &outputBufferBinding };
dmlBindingTable->BindOutputs(1, &outputBindingDesc);
L’une des étapes de création d’un opérateur DirectML (voir IDMLDevice ::CreateOperator) consiste à déclarer une ou plusieurs structures DML_BUFFER_TENSOR_DESC pour décrire les mémoires tampons de données tensoratrices que l’opérateur prend et retourne. Ainsi que le type et la taille de la mémoire tampon tensoriel, vous pouvez éventuellement spécifier le flag DML_TENSOR_FLAG_OWNED_BY_DML.
DML_TENSOR_FLAG_OWNED_BY_DML indique que les données de tenseur devraient être détenues et gérées par DirectML. DirectML effectue une copie des données tensorielles pendant l’initialisation de l’opérateur et les stocke dans la ressource persistante. Cela permet à DirectML d’effectuer un reformatage des données de tenseur dans d’autres formes plus efficaces. La définition de cet indicateur peut augmenter les performances, mais elle est généralement utile uniquement pour les tenseurs dont les données ne changent pas pour la durée de vie de l’opérateur (par exemple, les tenseurs de poids). Et l’indicateur peut uniquement être utilisé sur les tenseurs d’entrée. Lorsque l’indicateur est défini sur une description de tenseur particulière, le tenseur correspondant doit être lié dans la table de liaison pendant l’initialisation de l’opérateur, et non lors de l’exécution (ce qui entraînera une erreur). C’est l’opposé du comportement par défaut (le comportement sans le DML_TENSOR_FLAG_OWNED_BY_DML), où le tenseur est censé être lié pendant l’exécution, et non pendant l’initialisation. Toutes les ressources liées à DirectML doivent être des ressources de tas PAR DÉFAUT ou PERSONNALISÉEs.
Pour plus d’informations, consultez IDMLBindingTable ::BindInputs et IDMLBindingTable ::BindOutputs.
Exécuter l'élément dispatchable
Transmettez votre table de liaison en tant que paramètre lorsque vous appelez IDMLCommandRecorder ::RecordDispatch.
Lorsque vous utilisez la table de liaison pendant un appel à IDMLCommandRecorder ::RecordDispatch, DirectML lie les descripteurs GPU correspondants au pipeline. Les handles de descripteur UC et GPU ne sont pas nécessaires pour pointer vers les mêmes entrées dans un tas de descripteurs. Toutefois, il incombe ensuite à votre application de s'assurer que toute la plage de descripteurs référencée par le handle de descripteur d'UC est copiée dans la plage référencée par le handle de descripteur GPU avant l'exécution à l'aide de cette table de liaison.
winrt::com_ptr<::ID3D12GraphicsCommandList> d3D12GraphicsCommandList;
// Code to create a Direct3D 12 command list goes here.
winrt::com_ptr<::IDMLCommandRecorder> dmlCommandRecorder;
// Code to create a DirectML command recorder goes here.
dmlCommandRecorder->RecordDispatch(
d3D12GraphicsCommandList.get(),
dmlOperatorInitializer.get(),
dmlBindingTable.get()
);
Enfin, fermez votre liste de commandes Direct3D 12 et envoyez-la pour l’exécution, comme vous le feriez pour toute autre liste de commandes.
Avant l'exécution de RecordDispatch sur le GPU, vous devez faire passer toutes les ressources liées vers l'état D3D12_RESOURCE_STATE_UNORDERED_ACCESS, ou vers un état pouvant être promu à D3D12_RESOURCE_STATE_UNORDERED_ACCESS, comme D3D12_RESOURCE_STATE_COMMON. Une fois cet appel terminé, les ressources restent dans l’état D3D12_RESOURCE_STATE_UNORDERED_ACCESS . La seule exception à ceci concerne les tas de chargement pour upload lorsqu'on exécute un initialiseur d’opérateur et alors qu’un ou plusieurs tenseurs ont le drapeau DML_TENSOR_FLAG_OWNED_BY_DML défini. Dans ce cas, tous les heaps de téléchargement destinés à l'entrée doivent être dans l'état D3D12_RESOURCE_STATE_GENERIC_READ et resteront dans cet état, comme cela est requis par tous les heaps de téléchargement. Si DML_EXECUTION_FLAG_DESCRIPTORS_VOLATILE n’a pas été définie lors de la compilation de l’opérateur, toutes les liaisons doivent être définies sur la table de liaisons avant que RecordDispatch soit appelée, sinon le comportement n’est pas défini. Sinon, si un opérateur prend en charge la liaison tardive, la liaison de ressources peut être différée jusqu’à ce que la liste de commandes Direct3D 12 soit envoyée à la file d’attente de commandes pour l’exécution.
RecordDispatch fonctionne logiquement comme un appel à ID3D12GraphicsCommandList::Dispatch. Par conséquent, les barrières de vue d’accès non ordonnée (UAV) sont nécessaires pour garantir l’ordre correct s’il existe des dépendances de données entre les répartitions. Cette méthode n’insère pas de barrières UAV sur les ressources d’entrée ni de sortie. Votre application doit s’assurer que les barrières UAV correctes sont effectuées sur toutes les entrées si leur contenu dépend d’une distribution en amont et de toutes les sorties s’il existe des distributions en aval qui dépendent de ces sorties.
Durée de vie et synchronisation des descripteurs et de la table de liaison
Un bon modèle mental pour la liaison dans DirectML est que, en arrière-plan, la table de liaison DirectML elle-même crée et gère des descripteurs d’accès non ordonnés (UAV) dans le tas de descripteurs que vous fournissez. Ainsi, toutes les règles Direct3D 12 ordinaires s’appliquent à la synchronisation de l’accès à ce tas et à ses descripteurs. Il incombe à votre application d’effectuer une synchronisation correcte entre le travail processeur et GPU qui utilise une table de liaison.
Une table de liaison ne peut pas remplacer un descripteur alors que le descripteur est en cours d’utilisation (par un frame précédent, par exemple). Par conséquent, si vous souhaitez réutiliser une pile de descripteurs déjà liée (par exemple, en appelant à nouveau Bind* sur une table de liaisons qui y pointe, ou en remplaçant manuellement la pile de descripteurs), vous devez attendre que le processus de dispatch qui utilise actuellement cette pile de descripteurs ait fini de s'exécuter sur le GPU. Une table de liaison ne maintient pas de référence forte sur le tas de descripteurs dans lequel elle écrit, vous ne devez donc pas libérer le tas de descripteurs visible par le nuanceur tant que tous les travaux utilisant cette table de liaison n'ont pas terminé leur exécution sur le GPU.
En revanche, alors qu’une table de liaison spécifie et gère un tas de descripteurs, la table ne contient pas elle-même de cette mémoire. Par conséquent, vous pouvez libérer ou réinitialiser une table de liaison à tout moment après avoir appelé IDMLCommandRecorder ::RecordDispatch avec celui-ci (vous n’avez pas besoin d’attendre que cet appel se termine sur le GPU, tant que les descripteurs sous-jacents restent valides).
La table de liaison ne conserve pas de références fortes sur les ressources liées à l’aide de celle-ci. Votre application doit s’assurer que les ressources ne sont pas supprimées tout en restant utilisées par le GPU. En outre, une table de liaison n’est pas thread safe : votre application ne doit pas appeler des méthodes sur une table de liaison simultanément à partir de différents threads sans synchronisation.
Et considérez que dans tous les cas, la liaison est nécessaire uniquement lorsque vous modifiez les ressources liées. Si vous n’avez pas besoin de modifier les ressources liées, vous pouvez effectuer une liaison une seule fois au démarrage et passer la même table de liaison chaque fois que vous appelez RecordDispatch.
Pour les charges de travail entrelacées d'apprentissage automatique et de rendu, assurez-vous simplement que les tables de liaison de chaque trame pointent vers des plages de tas de descripteur qui ne sont pas déjà utilisées sur le GPU.
Spécifiez éventuellement des liaisons d’opérateur à liaison tardive
Si vous travaillez avec un opérateur compilé (plutôt qu'avec un initialiseur d'opérateur), vous avez la possibilité de spécifier une liaison tardive pour l'opérateur. Sans liaison différée, vous devez définir toutes les liaisons sur la table de liaisons avant d’enregistrer une opération dans une liste de commandes. Avec la liaison tardive, vous pouvez définir (ou modifier) des liaisons sur des opérateurs que vous avez déjà enregistrés dans une liste de commandes, avant qu’elles n’ont été envoyées à la file d’attente de commandes.
Pour spécifier la liaison tardive, appelez IDMLDevice::CompileOperator avec un flags argument de DML_EXECUTION_FLAG_DESCRIPTORS_VOLATILE.