Partager via


DXGKDDI_BUILDPAGINGBUFFER fonction de rappel (d3dkmddi.h)

La fonction DxgkDdiBuildPagingBuffer génère des mémoires tampons de pagination pour les opérations de mémoire.

Syntaxe

DXGKDDI_BUILDPAGINGBUFFER DxgkddiBuildpagingbuffer;

NTSTATUS DxgkddiBuildpagingbuffer(
  [in]     IN_CONST_HANDLE hAdapter,
  [in/out] IN_PDXGKARG_BUILDPAGINGBUFFER pBuildPagingBuffer
)
{...}

Paramètres

[in] hAdapter

Handle vers un bloc de contexte associé à un adaptateur d’affichage. Le pilote miniport d’affichage a précédemment fourni ce handle au sous-système du noyau graphique Microsoft DirectX dans le paramètre de sortie MiniportDeviceContext de la fonction DxgkDdiAddDevice .

[in/out] pBuildPagingBuffer

Pointeur vers une structure DXGKARG_BUILDPAGINGBUFFER qui contient des informations pour la création d’une mémoire tampon de pagination.

Valeur retournée

DxgkDdiBuildPagingBuffer retourne l’une des valeurs suivantes :

Code de retour Description
STATUS_SUCCESS DxgkDdiBuildPagingBuffersuccessfully a créé une mémoire tampon de pagination.
STATUS_GRAPHICS_ALLOCATION_BUSY Le GPU utilise actuellement l’allocation pour la mémoire tampon de pagination.
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER Plus d’espace est nécessaire dans la mémoire tampon de pagination (autrement dit, dans le membre pDmaBuffer de la structure DXGKARG_BUILDPAGINGBUFFER vers laquelle pointe le paramètre pBuildPagingBuffer).

Remarques

La fonction DxgkDdiBuildPagingBuffer est appelée pour créer des mémoires tampons d’accès direct à la mémoire (DMA) à usage spécial appelées mémoire tampons de pagination. Une mémoire tampon de pagination contient une opération qui déplace le contenu de parties des allocations :

  • Dans un segment d’une allocation.
  • Entre les segments d’allocations.
  • À partir d’un segment d’une allocation à la mémoire système.
  • De la mémoire système à un segment d’une allocation.

Le pilote de miniport d’affichage doit écrire l’instruction d’unité de traitement graphique (GPU) appropriée dans la mémoire tampon de pagination fournie (dans le membre pDmaBuffer de DXGKARG_BUILDPAGINGBUFFER) en fonction de l’opération de pagination demandée ; puis le pilote doit retourner la mémoire tampon de pagination au gestionnaire de mémoire vidéo (qui fait partie de Dxgkrnl.sys). Le planificateur GPU (qui fait également partie de Dxgkrnl.sys) appelle ensuite la fonction DxgkDdiSubmitCommand du pilote pour demander que le pilote envoie la mémoire tampon de pagination en tant que mémoire tampon DMA normale au GPU.

Note Avant que le gestionnaire de mémoire vidéo envoie la mémoire tampon de pagination, il appelle la fonction DxgkDdiPatch du pilote pour affecter (c’est-à-dire corriger) des adresses physiques à la mémoire tampon de pagination ; Toutefois, dans l’appel à DxgkDdiPatch, le gestionnaire de mémoire vidéo ne fournit pas de listes d’emplacements de correctif. La fonction DxgkDdiPatch du pilote peut effectuer des mises à jour de dernière minute de la mémoire tampon de pagination ; Toutefois, la fonction DxgkDdiPatch du pilote ne peut pas modifier la taille de la mémoire tampon de pagination.
 
Lorsque le pilote génère correctement la mémoire tampon de pagination, le DxgkDdiBuildPagingBuffer du pilote doit mettre à jour pDmaBuffer pour pointer au-delà du dernier octet écrit dans la mémoire tampon de pagination, puis retourner STATUS_SUCCESS. Étant donné que DxgkDdiBuildPagingBuffer ne peut échouer que s’il manque d’espace dans la mémoire tampon de pagination, le pilote doit toujours vérifier que la mémoire tampon de pagination dispose de suffisamment d’espace avant d’écrire dans la mémoire tampon. S’il ne reste pas suffisamment d’espace dans la mémoire tampon de pagination, le pilote doit retourner STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER. Le gestionnaire de mémoire vidéo acquiert ensuite une nouvelle mémoire tampon de pagination et appelle à nouveau la fonction DxgkDdiBuildPagingBuffer du pilote pour remplir la nouvelle mémoire tampon de pagination en fonction de l’opération de pagination demandée. Notez que pour une opération de pagination demandée donnée qui remplit plusieurs mémoires tampons de pagination, le planificateur appelle la fonction DxgkDdiSubmitCommand du pilote plusieurs fois pour chaque mémoire tampon de pagination partielle afin d’envoyer chaque mémoire tampon indépendamment.

Si DxgkDdiBuildPagingBuffer détermine qu’une opération de pagination nécessite plusieurs mémoires tampons de pagination, le pilote peut spécifier des informations dans le membre MultipassOffset de DXGKARG_BUILDPAGINGBUFFER et peut utiliser ces informations dans plusieurs itérations de l’opération de pagination. Le gestionnaire de mémoire vidéo initialise les informations dans MultipassOffset à zéro avant la première demande d’opération de pagination et ne modifie pas les informations dans MultipassOffset entre les itérations. Par conséquent, le pilote peut utiliser MultipassOffset pour enregistrer la progression entre les itérations. Par exemple, le pilote peut stocker le numéro de page qui a été transféré pour le dernier transfert paginé.

Une mémoire tampon de pagination est actuellement conçue pour les types d’opérations suivants :

  • Transférer

    L’opération de transfert déplace le contenu d’une allocation d’un emplacement à un autre. Cette opération est le type d’opération de mémoire le plus courant.

    Une allocation est toujours entièrement transférée d’un emplacement à un autre. Toutefois, en raison de contraintes de mémoire, le transfert d’une allocation peut être divisé en plusieurs sous-transferts (autrement dit, une partie de l’allocation est déplacée de l’emplacement A vers B, puis la partie suivante est déplacée, et ainsi de suite, jusqu’à ce que l’allocation entière soit transférée). Le premier sous-transfert d’une allocation est marqué avec l’indicateur de champ bit TransferStart dans le membre Indicateurs du membre Transfer de DXGKARG_BUILDPAGINGBUFFER ; le dernier sous-transfert d’une allocation est marqué avec l’indicateur de champ de bits TransferEnd . Le conducteur est assuré de recevoir la fin d’un transfert en attente (c’est-à-dire le dernier sous-transfert) avant le début d’un nouveau transfert.

    Chaque sous-transfert peut nécessiter l’exécution de plusieurs appels à DxgkDdiBuildPagingBuffer (par exemple, le pilote peut manquer d’espace tampon DMA). Par conséquent, le pilote peut recevoir l’indicateur TransferStart dans plusieurs appels à DxgkDdiBuildPagingBuffer jusqu’à ce que le pilote reçoive l’indicateur TransferEnd dans un appel à DxgkDdiBuildPagingBuffer. La réception de l’indicateur TransferStart plusieurs fois n’indique pas le début de plusieurs nouveaux transferts ; elle indique que les sous-transferts pour l’allocation nécessitent plusieurs itérations (par exemple, si le pilote n’a plus d’espace de mémoire tampon DMA). Le pilote peut utiliser le membre MultipassOffset de DXGKARG_BUILDPAGINGBUFFER pour suivre la progression d’un sous-transfert particulier sur plusieurs itérations de DxgkDdiBuildPagingBuffer.

    En règle générale, un transfert se produit en une seule opération. Dans ce cas, les indicateurs de champ binaire TransferStart et TransferEnd sont définis.

    Dans certains scénarios, le pilote peut être nécessaire pour configurer des ressources matérielles lorsque certaines allocations sont paginées ou hors de mémoire. Par défaut, le GPU peut utiliser l’allocation référencée lors de l’appel à DxgkDdiBuildPagingBuffer. Dans ces scénarios, le pilote peut exiger que l’allocation soit inactive avant que le pilote programme les ressources matérielles requises (autrement dit, la programmation des ressources matérielles ne peut pas être mise en file d’attente dans la mémoire tampon DMA fournie). Pour ces scénarios, le pilote peut échouer l’appel à DxgkDdiBuildPagingBuffer avec STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si le pilote retourne STATUS_GRAPHICS_ALLOCATION_BUSY, le gestionnaire de mémoire vidéo attend que le GPU soit terminé avec une référence à l’allocation actuelle, puis appelle à nouveau la fonction DxgkDdiBuildPagingBuffer du pilote. Dans le deuxième appel à DxgkDdiBuildPagingBuffer, le gestionnaire de mémoire vidéo définit l’indicateur de champ binaire AllocationIsIdle dans le membre Flags du membre Transfer de DXGKARG_BUILDPAGINGBUFFER pour indiquer que l’allocation référencée est inactive. Si l’indicateur d’inactivité n’est pas défini, le pilote doit toujours déterminer que l’allocation est actuellement occupée ou peut être bientôt occupée. Si l’indicateur d’inactivité est défini, le gestionnaire de mémoire vidéo garantit que l’allocation référencée reste inactive pendant la durée de l’appel à DxgkDdiBuildPagingBuffer.

    Si le membre hAllocation de DXGKARG_BUILDPAGINGBUFFER a la valeur NULL, le pilote doit copier les données de la source vers la destination sans effectuer de tourbillon ni de mosaïchage.

  • Remplir

    L’opération de remplissage remplit une allocation avec un modèle spécifié. L’opération de remplissage est utilisée pour configurer le contenu initial d’une allocation. Lorsque le contenu de l’allocation est rempli, il est garanti que l’allocation soit inactive (c’est-à-dire qu’elle n’est pas utilisée par le GPU). L’opération de remplissage ne peut être effectuée que sur un segment de mémoire. Le gestionnaire de mémoire vidéo ne demande jamais que le pilote miniport d’affichage remplisse un segment d’ouverture.

  • Ignorer le contenu

    L’opération discard-content avertit le pilote qu’une allocation est ignorée à partir de l’emplacement actuel de l’allocation dans un segment de mémoire. Autrement dit, l’allocation est supprimée et non copiée dans la mémoire système.

    Dans certains scénarios, le pilote peut être nécessaire pour configurer des ressources matérielles lorsque certaines allocations sont paginées ou hors de mémoire. Par défaut, le GPU peut utiliser l’allocation référencée lors de l’appel à DxgkDdiBuildPagingBuffer. Dans ces scénarios, le pilote peut exiger que l’allocation soit inactive avant que le pilote programme les ressources matérielles requises (autrement dit, la programmation des ressources matérielles ne peut pas être mise en file d’attente dans la mémoire tampon DMA fournie). Pour ces scénarios, le pilote peut échouer l’appel à DxgkDdiBuildPagingBuffer avec STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si le pilote retourne STATUS_GRAPHICS_ALLOCATION_BUSY, le gestionnaire de mémoire vidéo attend que le GPU soit terminé avec une référence à l’allocation actuelle, puis appelle à nouveau la fonction DxgkDdiBuildPagingBuffer du pilote. Dans le deuxième appel à DxgkDdiBuildPagingBuffer, le gestionnaire de mémoire vidéo définit l’indicateur de champ binaire AllocationIsIdle dans le membre Flags du membre DiscardContent de la structure DXGKARG_BUILDPAGINGBUFFER pour indiquer que l’allocation référencée est inactive. Si l’indicateur d’inactivité n’est pas défini, le pilote doit toujours déterminer que l’allocation est actuellement occupée ou peut être bientôt occupée. Si l’indicateur d’inactivité est défini, le gestionnaire de mémoire vidéo garantit que l’allocation référencée reste inactive pendant la durée de l’appel à DxgkDdiBuildPagingBuffer.

  • Lecture physique

    L’opération de lecture physique lit à partir d’une adresse mémoire physique spécifiée. Le pilote est invité à programmer le GPU pour l’opération. La taille de la mémoire physique à accéder pour la lecture peut être comprise entre 1 octet et 8 octets. Étant donné que les données lues ne sont pas pertinentes, DxgkDdiBuildPagingBuffer n’est pas nécessaire pour retourner les données. Toutefois, dans les scénarios où le processeur tente de lire à partir de la mémoire AGP après que le GPU a écrit dans cette mémoire AGP, l’opération de lecture physique est essentielle pour garantir la cohérence de la mémoire.

  • Écrire physique

    L’opération d’écriture physique écrit dans une adresse physique spécifiée. Le pilote est invité à programmer le GPU pour l’opération. La taille de la mémoire physique à accéder pour l’opération d’écriture peut être comprise entre 1 octet et 8 octets. Étant donné que les données écrites ne sont pas pertinentes, DxgkDdiBuildPagingBuffer peut écrire toutes les données en mémoire. Toutefois, dans les scénarios où le processeur tente de lire à partir de la mémoire AGP après que le GPU a écrit dans cette mémoire AGP, l’opération physique d’écriture est essentielle pour garantir la cohérence de la mémoire.

  • Segment d’ouverture de carte

    L’opération map-aperture-segment mappe une liste de descripteurs mémoire (MDL) spécifiée dans un segment d’ouverture spécifié à un décalage de segment spécifié pour un nombre spécifié de pages. Si l’indicateur de champ de bits CacheCoherent est défini dans le membre Flags du membre MapApertureSegment de la structure DXGKARG_BUILDPAGINGBUFFER , le pilote doit s’assurer que la cohérence du cache est appliquée sur les pages mappées ; sinon, la cohérence du cache n’est pas requise pour les pages qui sont mappées.

    Note L’indicateur de champ de bits CacheCoherent est défini uniquement lorsque la mémoire pouvant être mise en cache est mappée dans un segment d’ouverture cohérent du cache et n’est jamais défini sur un segment d’ouverture non cohérent dans le cache ou sur une allocation combinée en écriture qui est mappée dans un segment cohérent du cache.
     
    Le pilote peut éventuellement utiliser les E/S mappées en mémoire (MMIO) pour configurer un segment d’ouverture. Le GPU n’accède pas à la plage d’ouverture au moment de la configuration. Toutefois, cette configuration d’ouverture ne doit pas interférer avec l’exécution du GPU. Le GPU ne sera pas inactif lorsque DxgkDdiBuildPagingBuffer est appelé avec le type d’opération DXGK_OPERATION_MAP_APERTURE_SEGMENT défini, et le GPU peut être occupé à accéder à d’autres parties du segment d’ouverture en cours de reconfiguration.
  • Annuler le mappage du segment d’ouverture

    L’opération unmap-aperture-segment annule le mappage d’une plage précédemment mappée d’un segment d’ouverture spécifié. Le pilote doit mapper la plage qui est non mappée à la page factice spécifiée par le membre DummyPage du membre UnmapApertureSegment de la structure DXGKARG_BUILDPAGINGBUFFER .

    Note Lorsque le pilote démasse la page factice, le pilote doit activer les accès GPU via la plage d’ouverture spécifiée afin que le sous-système du noyau graphique DirectX puisse détecter les problèmes d’altération. Des tests de conformité existent pour case activée cette situation.
     
    Le gestionnaire de mémoire vidéo utilise la page factice qui se trouve dans la partie non mappée de l’ouverture pour déterminer les difficultés d’accès du gestionnaire de mémoire au segment d’ouverture.

    Le pilote peut éventuellement utiliser MMIO pour configurer un segment d’ouverture. Le GPU n’accède pas à la plage d’ouverture au moment de la configuration. Toutefois, cette configuration d’ouverture ne doit pas interférer avec l’exécution du GPU. Le GPU ne sera pas inactif lorsque DxgkDdiBuildPagingBuffer est appelé avec le type d’opération DXGK_OPERATION_UNMAP_APERTURE_SEGMENT défini, et le GPU peut être occupé à accéder à d’autres parties du segment d’ouverture en cours de reconfiguration.

  • Transfert de verrou spécial

    L’opération special-lock-transfer est similaire à l’opération de transfert standard. Toutefois, au lieu de transférer le contenu de l’allocation depuis ou vers le magasin de stockage normal de l’allocation, l’opération de verrouillage spécial transfère le contenu de l’allocation depuis ou vers l’autre adresse virtuelle qui a été configurée pour l’allocation lorsque la fonction pfnLockCb a été appelée avec l’indicateur de champ de bits UseAlternateVA .

    L’opération special-lock-transfer se produit uniquement dans l’un des scénarios suivants :

    • L’allocation est actuellement accessible par le processeur avec une autre adresse virtuelle et est en cours de suppression.
    • Une allocation précédemment supprimée, telle que la situation décrite dans la puce précédente, est paginée.
    Les pilotes qui ne prennent pas en charge l’utilisation de l’indicateur de champ binaire UseAlternateVA ne seront pas appelés pour effectuer une opération de verrouillage-transfert spécial.

    Dans certains scénarios, le pilote peut être nécessaire pour configurer des ressources matérielles lorsque certaines allocations sont paginées ou hors de mémoire. Par défaut, le GPU peut utiliser l’allocation référencée lors de l’appel à DxgkDdiBuildPagingBuffer. Dans ces scénarios, le pilote peut exiger que l’allocation soit inactive avant que le pilote programme les ressources matérielles requises (autrement dit, la programmation des ressources matérielles ne peut pas être mise en file d’attente dans la mémoire tampon DMA fournie). Pour ces scénarios, le pilote peut échouer l’appel à DxgkDdiBuildPagingBuffer avec STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si le pilote retourne STATUS_GRAPHICS_ALLOCATION_BUSY, le gestionnaire de mémoire vidéo attend que le GPU soit terminé avec une référence à l’allocation actuelle, puis appelle à nouveau la fonction DxgkDdiBuildPagingBuffer du pilote. Dans le deuxième appel à DxgkDdiBuildPagingBuffer, le gestionnaire de mémoire vidéo définit l’indicateur de champ binaire AllocationIsIdle dans le membre Flags du membre SpecialLockTransfer de la structure DXGKARG_BUILDPAGINGBUFFER pour indiquer que l’allocation référencée est inactive. Si l’indicateur d’inactivité n’est pas défini, le pilote doit toujours déterminer que l’allocation est actuellement occupée ou peut être bientôt occupée. Si l’indicateur d’inactivité est défini, le gestionnaire de mémoire vidéo garantit que l’allocation référencée reste inactive pendant la durée de l’appel à DxgkDdiBuildPagingBuffer.

Notez que si le pilote doit utiliser une ouverture matérielle pour linéariser une allocation swizzled à laquelle une application peut accéder directement, il doit annuler cette allocation pendant que le pilote transfère l’allocation à la mémoire système pour maintenir la cohérence de l’adresse virtuelle de l’allocation. Le pilote doit annuler l’allocation, car une éviction peut se produire pendant que l’application accède à l’allocation.

Le gestionnaire de mémoire du système garantit que le transfert est invisible pour l’application. Toutefois, étant donné que l’allocation est en mémoire système et que l’adresse virtuelle de l’allocation ne peut plus passer par l’ouverture matérielle, le pilote doit s’assurer que l’ordre des octets dans la mémoire système correspond à ce qui était visible à travers l’ouverture.

DxgkDdiBuildPagingBuffer doit être rendu paginable.

Exemples

L’exemple de code suivant montre comment utiliser DxgkDdiBuildPagingBuffer.

NTSTATUS ntStatus;
DXGKARG_BUILDPAGINGBUFFER param;

// The driver receives the following paging operation to build:
//
param.Flags = 0;
param.pDmaBuffer= CurrentPagingBuffer;
param.DmaSize = CurrentPagingBufferSizeLeft;
param.pDmaBufferPrivateData = CurrentPagingBufferPrivateData; 
param.DmaBufferPrivateDataSize = CurrentPagingBufferPrivateDataSizeLeft; 
param.Operation = DXGK_OPERATION_TRANSFER; 
param.Transfer.Flags = 0; 
param.Transfer.TransferOffset = CurrentOffsetInAllocationBeingTransfered; 
param.Transfer.hAllocation = DriverContextForAllocationBeingMoved; 
param.Transfer.Source.SegmentId = 0; // Source is an MDL. 
param.Transfer.Source.pMdl = MDLDescribingPagesForAllocationBeingMoved; 
param.Transfer.Destination.SegmentId = 1; // Source to segment #1. 
param.Transfer.Destination.SegmentAddress = 0; // Source to offset 0 of segment #1.

// The driver receives MultipassOffset when it is initialized to zero 
// and uses it for multiple iterations of the paging operation.
//
param.MultipassOffset = 0;

do {
    // Call the driver's BuildPagingBuffer function to build a paging buffer.
    //
    ntStatus = BuildPagingBuffer(hAdapter, &param);
    // BuildPagingBuffer updates the size that is left in the 
    //  paging buffer with the amount of bytes that were written.
    //
    if (NT_SUCCESS(ntStatus)) {
        //
        // If STATUS_SUCCESS, batch the paging buffer to the 
        // scheduler after multiple paging operations are batched.
    }
    else if (ntStatus == STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER) {

        //
        // If STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER, submit the current paging buffer to the scheduler to let 
        // the GPU start working on a partial transfer.
 
        VidSchSubmitPagingBuffer(CurrentPagingBuffer, CurrentPagingBufferSizeLeft);
 
        // Acquire a new paging buffer to complete the transfer.
        //
        VidMmAcquirePagingBuffer(&CurrentPagingBuffer, &CurrentPagingBufferSizeLeft);
    }
    else {
        //
        // A critical failure occurred, so bugcheck the system. 
        // This situation should never occur because the driver can 
        // fail the call only if it requires more DMA buffer space.
    }
} while(!NT_SUCCESS(ntStatus))

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows Vista
Plateforme cible Desktop (Expérience utilisateur)
En-tête d3dkmddi.h
IRQL PASSIVE_LEVEL

Voir aussi

DXGKARG_BUILDPAGINGBUFFER

DxgkDdiAddDevice

DxgkDdiPatch

DxgkDdiSubmitCommand

pfnLockCb