Liaison dans DirectML

Dans DirectML, le terme de liaison fait référence au fait d’attacher des ressources au pipeline pour que le GPU soit utilisé 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 concernant 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 la liaison

La liste des étapes ci-dessous contient une description générale des tâches liées à la liaison. Vous devez suivre ces étapes chaque fois que vous exécutez un répartissable : un répartissable est soit un initialiseur d’opérateur soit 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 de code illustrant les extraits de code extraits de l’exemple de code d’application DirectML minimal.

  • Appelez IDMLDispatchable::GetBindingProperties sur le répartissable pour déterminer le nombre de descripteurs dont il a besoin, ainsi que ses besoins en ressources temporaires/persistantes.
  • Créez un tas du 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 structureDML_BINDING_TABLE_DESC pour décrire votre table de liaison, y compris le sous-ensemble des descripteurs vers lequel il pointe dans le tas du descripteur.
  • Créez des ressources temporaires/persistantes en tant que ressources de mémoire tampon Direct3D 12, décrivez-les avec les structures DML_BUFFER_BINDING et DML_BINDING_DESC, puis ajoutez-les à la table de liaison.
  • Si le répartissable est un opérateur compilé, créez une mémoire tampon des éléments du tenseur en tant que ressource de mémoire tampon Direct3D 12. Remplissez/chargez-le, décrivez-le avec des structures DML_BUFFER_BINDING et DML_BINDING_DESC, puis ajoutez-le à la table de liaison.
  • Transférez votre table de liaison en tant que paramètre lorsque vous appelez IDMLCommandRecorder::RecordDispatch.

Récupérez les propriétés de liaison d’un répartissable

La structure DML_BINDING_PROPERTIES décrit les besoins de liaison d’un répartissable d’opérateur (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 au répartissable, ainsi que la taille en octets de toutes les ressources temporaires et/ou persistantes dont elle a besoin.

Remarque

Même pour plusieurs opérateur appartenant au même type d’opérateurs, ne partez pas du principe qu’ils ont les mêmes exigences de liaison. Interrogez les propriétés de liaison pour chaque initialiseur et chaque 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 valeur descriptorCount que vous récupérez ici détermine la taille (minimale) du tas du descripteur et de la table de liaison que vous créez dans les deux étapes suivantes.

DML_BINDING_PROPERTIES contient également un membre TemporaryResourceSize, qui est la taille minimale en octets de la ressource temporaire qui doit être liée à la table de liaison pour cet objet répartissable. La valeur zéro signifie qu’une ressource temporaire n’est pas requise.

Et un membre PersistentResourceSize, qui est la taille minimale en octets de la ressource persistante qui doit être liée à la table de liaison pour cet objet répartissable. La valeur zéro signifie qu’une ressource persistante n’est pas requise. 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 à ce sujet. 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 alors pas garantis identiques.

Décrire, créer et lier un tas du descripteur

En termes de descripteurs, votre responsabilité commence et se termine par le tas du descripteur lui-même. DirectML lui-même s’occupe de la création et de la gestion des descripteurs à l’intérieur du segment de mémoire que vous fournissez.

Utilisez donc une structure D3D12_DESCRIPTOR_HEAP_DESC pour décrire un segment de mémoire suffisamment grand pour le nombre de descripteurs dont le répartissable a besoin. Ensuite, créez-le avec ID3D12Device::CreateDescriptorHeap. Enfin, appelez ID3D12GraphicsCommandList::SetDescriptorHeaps pour lier votre tas du 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 liez au pipeline pour un répartissable à utiliser. Ces ressources peuvent être des tenseurs d’entrée et de sortie (ou d’autres paramètres) pour un opérateur, ou il peut s’agir de différentes ressources persistantes et temporaires avec lesquelles un répartissable fonctionne.

Utilisez la structure DML_BINDING_TABLE_DESC pour décrire votre table de liaison, y compris le répartissable pour lequel la table de liaison représentera les liaisons, et la plage de descripteurs (à partir du tas du descripteur que vous venez de créer) à laquelle vous souhaitez que la table de liaison fasse référence (et dans laquelle DirectML peut écrire des descripteurs). La valeur descriptorCount (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 de la table de liaison (dans les descripteurs) requise pour l’objet répartissable. Ici, nous utilisons cette valeur pour indiquer le nombre maximal de descripteurs que DirectML est autorisé à écrire dans notre segment de mémoire, à partir du début des handles de descripteur des UC et GPU fournis.

Appelez ensuite IDMLDevice::CreateBindingTable pour créer la table de liaison DirectML. Dans les étapes suivantes, une fois que nous avons créé d’autres ressources pour le répartissable, nous allons ajouter ces ressources à la table de liaison.

Au lieu de transférer un DML_BINDING_TABLE_DESC à cet appel, vous pouvez transférer nullptr, indiquant 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 segment de mémoire n’est pas spécifié. Par conséquent, votre application ne doit pas remplacer les descripteurs encapsulés par la table de liaison. Les handles de descripteur UC et GPU fournis peuvent provenir de différents tas, mais il incombe ensuite à votre application de s’assurer que toute la plage de descripteur référencée par le handle de descripteur d’UC est copiée dans la plage référencée par le descripteur GPU avant l’exécution à l’aide de cette table de liaison. Le tas du descripteur à partir duquel les handles sont fournis doit avoir le type D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV. En outre, le segment de mémoire référencé par le tas GPUDescriptorHandle doit être un tas du descripteur visible par le nuanceur.

Vous pouvez réinitialiser une table de liaison pour supprimer toutes les ressources que vous y avez ajoutées, 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 un autre répartissable). 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 répartissable contient la taille en octets de toutes les ressources temporaires et/ou persistantes dont le répartissable a besoin. 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 la répartissable. Nous décrivons comment nous souhaitons lier la ressource, puis nous ajoutons cette liaison à la table de liaison.

Comme nous lions une seule ressource 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 mémoire tampon unique). Il s’agit du but de la structure DML_BUFFER_ARRAY_BINDING.

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 membre Type du DML_BINDING_DESC sur DML_BINDING_TYPE_BUFFER ou sur DML_BINDING_TYPE_BUFFER_ARRAY. Vous pouvez ensuite définir 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 scratch utilisée en interne pendant l’exécution de l’opérateur. Vous n’avez donc pas besoin de vous soucier de son contenu. Vous n’avez pas non plus besoin de le conserver après votre appel à IDMLCommandRecorder::RecordDispatch soit terminé sur le GPU. Cela signifie que votre application peut libérer ou remplacer la ressource temporaire entre les répartitions de l’opérateur compilé. La plage de mémoires tampons fournie doit être liée, car la ressource temporaire doit avoir son décalage de début aligné avec DML_TEMPORARY_BUFFER_ALIGNMENT. Le type du tas sous-jacent à la mémoire tampon doit être D3D12_HEAP_TYPE_DEFAULT.

Cependant, si le répartissable signale une taille non nulle pour sa ressource persistante de plus longue durée, alors la procédure est un peu différente. Vous devez créer une mémoire tampon et décrire une liaison en suivant le modèle indiqué ci-dessus. Ajoutez cette liaison à la table de liaison de votre opérateur initialiseur avec un appel à IDMLBindingTable::BindOutputs, car c’est l’opérateur qui initialise la ressource persistante. Ensuite, ajoutez-la à la table de liaison de votre opérateur compilé avec un appel à 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é le fait. 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 en modifier le contenu. La ressource persistante est généralement utilisée par DirectML pour stocker des tables de choix ou d’autres données de longue durée qui sont 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émoires tampons fournie à lier, car la mémoire tampon persistante doit avoir son 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 utilisez un opérateur compilé (plutôt qu’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, tenseurs facultatifs compris. 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 tenseur est une mémoire tampon qui contient les valeurs d’élément individuelles du tenseur. Vous chargez et lisez de telles mémoires tampons vers/depuis le GPU à l’aide des techniques Direct3D 12 classiques (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 à l’aide de 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 d’UC.

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 du tenseur que l’opérateur prend et retourne. Ainsi que le type et la taille de la mémoire tampon de tenseur, vous pouvez éventuellement spécifier l’indicateur DML_TENSOR_FLAG_OWNED_BY_DML.

DML_TENSOR_FLAG_OWNED_BY_DML indique que les données de tenseur doivent être détenues et managées par DirectML. DirectML effectue une copie des données de tenseur 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 vers d’autres formes plus efficaces. La définition de cet indicateur peut augmenter les performances, mais elle est généralement utile pour les tenseurs dont les données ne changent pas durant toute la vie de l’opérateur seulement (par exemple, les tenseurs de poids). L’indicateur ne peut être utilisé que sur des tenseurs d’entrée. Lorsque l’indicateur est défini sur une description de tenseur particulière, le tenseur correspondant doit être lié à la table de liaison pendant l’initialisation de l’opérateur, et non lors de l’exécution (ce qui entraînerait une erreur). C’est l’opposé du comportement par défaut (le comportement sans l’indicateur DML_TENSOR_FLAG_OWNED_BY_DML), durant lequel 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ÉE.

Pour plus d’informations, consultez IDMLBindingTable::BindInputs et IDMLBindingTable::BindOutputs.

Exécuter le répartissable

Transférez 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 doivent pas nécessairement pointer vers les mêmes entrées du tas du descripteur, mais il incombe ensuite à votre application de s’assurer que toute la plage de descripteur référencée par le handle de descripteur d’UC est copiée dans la plage référencée par le 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 à l’état D3D12_RESOURCE_STATE_UNORDERED_ACCESS, ou à un état pouvant être implicitement 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 le chargement de tas liés lors de l’exécution d’un initialiseur d’opérateur, tandis qu’un ou plusieurs tenseurs ont l’indicateur DML_TENSOR_FLAG_OWNED_BY_DML défini. Dans ce cas, tous les tas de chargement liés à l’entrée doivent être dans l’état D3D12_RESOURCE_STATE_GENERIC_READ et y rester, comme requis par tous les chargements de tas. Si DML_EXECUTION_FLAG_DESCRIPTORS_VOLATILE n’a pas été défini lors de la compilation de l’opérateur, toutes les liaisons doivent être définies sur la table de liaison avant que RecordDispatch ne soit appelée, sinon le comportement n’est pas défini. Autrement, 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.

Logiquement, RecordDispatch agit 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 ou de sortie. Votre application doit s’assurer que les bonnes barrières UAV sont effectuées sur toutes les entrées si leur contenu dépend d’une répartition en amont et sur toutes les sorties en cas de répartitions en aval qui dépendent de ces sorties.

Durée de vie et synchronisation des descripteurs et de la table de liaison

Une bonne représentation mentale des liaisons dans DirectML est que, en arrière-plan, la table de liaison DirectML crée et gère elle-même les descripteurs de vue d’accès non ordonnés (UAV) à l’intérieur du tas du descripteur que vous fournissez. Ainsi, toutes les règles Direct3D 12 habituelles s’appliquent à la synchronisation des accès à ce tas et à ses descripteurs. Il incombe à votre application d’effectuer une synchronisation correcte entre le travail UC et le travail GPU qui utilise une table de liaison.

Une table de liaison ne peut pas remplacer un descripteur lorsque le descripteur est en cours d’utilisation (par un frame précédent, par exemple). Par conséquent, si vous souhaitez réutiliser un tas de descripteur déjà lié (par exemple, en appelant Bind* à nouveau sur une table de liaison qui pointe vers celle-ci, ou en remplaçant manuellement le tas de descripteur), vous devez attendre que le répartissable qui utilise actuellement le tas du descripteur ait fini de s'exécuter sur le GPU. Une table de liaison ne conserve pas de référence forte sur le tas du descripteur dans lequel elle écrit. Vous ne devez donc pas libérer le tas du descripteur visible par le nuanceur de stockage tant que tout le travail effectué à l’aide de cette table de liaison n’a pas terminé l’exécution sur le GPU.

En revanche, alors qu’une table de liaison spécifie et gère un tas du descripteur, la table ne contient pas elle-même 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 alors qu’elles sont 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.

Dans tous les cas, une re-liaison est uniquement nécessaire lorsque vous modifier des ressources qui sont liées. Si vous n’avez pas besoin de modifier les ressources liées, vous pouvez effectuer une liaison lors du démarrage et passer la même table de liaison chaque fois que vous appelez RecordDispatch.

Pour les charges de travail d’apprentissage automatique et de rendu entrelacées, assurez-vous simplement que les tables de liaison de chaque image pointent vers des plages de tas du descripteur qui ne sont pas déjà utilisées sur le GPU.

Spécifiez éventuellement des liaisons d’opérateur à liaison tardive

Si vous traitez d’un opérateur compilé (plutôt qu’avec un initialiseur d’opérateur), vous avez la possibilité de spécifier la liaison tardive pour l’opérateur. Sans liaison tardive, vous devez définir toutes les liaisons sur la table de liaisons avant d’enregistrer un opérateur dans une liste de commandes. Avec une 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 ne soient envoyées à la file d’attente de commandes.

Pour spécifier une liaison tardive, appelez IDMLDevice::CompileOperator avec un argument flags de DML_EXECUTION_FLAG_DESCRIPTORS_VOLATILE.

Voir aussi