Compartilhar via


DXGKDDI_BUILDPAGINGBUFFER função de retorno de chamada (d3dkmddi.h)

A função DxgkDdiBuildPagingBuffer cria buffers de paginação para operações de memória.

Sintaxe

DXGKDDI_BUILDPAGINGBUFFER DxgkddiBuildpagingbuffer;

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

Parâmetros

[in] hAdapter

Um identificador para um bloco de contexto associado a um adaptador de exibição. O driver de miniporto de exibição forneceu anteriormente esse identificador para o subsistema de kernel de elementos gráficos do Microsoft DirectX no parâmetro de saída MiniportDeviceContext da função DxgkDdiAddDevice .

[in/out] pBuildPagingBuffer

Um ponteiro para uma estrutura DXGKARG_BUILDPAGINGBUFFER que contém informações para criar um buffer de paginação.

Retornar valor

DxgkDdiBuildPagingBuffer retorna um dos seguintes valores:

Código de retorno Descrição
STATUS_SUCCESS DxgkDdiBuildPagingBuffersuccessfully criou um buffer de paginação.
STATUS_GRAPHICS_ALLOCATION_BUSY Atualmente, a GPU está usando a alocação para o buffer de paginação.
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER Mais espaço é necessário no buffer de paginação (ou seja, no membro pDmaBuffer da estrutura DXGKARG_BUILDPAGINGBUFFER à qual o parâmetro pBuildPagingBuffer aponta).

Comentários

A função DxgkDdiBuildPagingBuffer é chamada para criar buffers de DMA (acesso direto à memória) de finalidade especial que são conhecidos como buffers de paginação. Um buffer de paginação contém uma operação que move o conteúdo de partes de alocações:

  • Dentro de um segmento de uma alocação.
  • Entre segmentos de alocações.
  • De um segmento de uma alocação para a memória do sistema.
  • Da memória do sistema a um segmento de uma alocação.

O driver de miniporto de exibição deve escrever a instrução de GPU (unidade de processamento gráfico) apropriada no buffer de paginação fornecido (no membro pDmaBuffer de DXGKARG_BUILDPAGINGBUFFER) de acordo com a operação de paginação solicitada; e, em seguida, o driver deve retornar o buffer de paginação de volta para o gerenciador de memória de vídeo (que faz parte de Dxgkrnl.sys). O agendador de GPU (que também faz parte do Dxgkrnl.sys) chama posteriormente a função DxgkDdiSubmitCommand do driver para solicitar que o driver envie o buffer de paginação como um buffer DMA regular para a GPU.

Nota Antes que o gerenciador de memória de vídeo envie o buffer de paginação, ele chama a função DxgkDdiPatch do driver para atribuir endereços físicos (ou seja, patch) ao buffer de paginação; no entanto, na chamada para DxgkDdiPatch, o gerenciador de memória de vídeo não fornece listas de localização de patch. A função DxgkDdiPatch do driver pode executar atualizações de última hora no buffer de paginação; no entanto, a função DxgkDdiPatch do driver não pode alterar o tamanho do buffer de paginação.
 
Quando o driver compila com êxito o buffer de paginação, o DxgkDdiBuildPagingBuffer do driver deve atualizar o pDmaBuffer para apontar para além do último byte gravado no buffer de paginação e retornar STATUS_SUCCESS. Como o DxgkDdiBuildPagingBuffer só poderá falhar se ficar sem espaço no buffer de paginação, o driver sempre deve verificar se o buffer de paginação tem espaço suficiente antes de gravar no buffer. Se não houver espaço suficiente no buffer de paginação, o driver deverá retornar STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER. Em seguida, o gerenciador de memória de vídeo adquiriria um novo buffer de paginação e chamaria a função DxgkDdiBuildPagingBuffer do driver novamente para preencher o novo buffer de paginação de acordo com a operação de paginação solicitada. Observe que para uma determinada operação de paginação solicitada que preenche vários buffers de paginação, o agendador chama a função DxgkDdiSubmitCommand do driver várias vezes para cada buffer de paginação parcial para enviar cada buffer de forma independente.

Se DxgkDdiBuildPagingBuffer determinar que uma operação de paginação requer mais de um buffer de paginação, o driver poderá especificar informações no membro multipassOffset do DXGKARG_BUILDPAGINGBUFFER e poderá usar essas informações em várias iterações da operação de paginação. O gerenciador de memória de vídeo inicializa as informações em MultipassOffset como zero antes da primeira solicitação de operação de paginação e não modifica as informações em MultipassOffset entre iterações. Portanto, o driver pode usar o MultipassOffset para salvar o progresso entre iterações. Por exemplo, o driver pode armazenar o número de página que foi transferido pela última vez para uma transferência baseada em página.

No momento, um buffer de paginação é criado para os seguintes tipos de operações:

  • Transferência

    A operação de transferência move o conteúdo de uma alocação de um local para outro. Essa operação é o tipo mais comum de operação de memória.

    Uma alocação é sempre totalmente transferida de um local para outro. No entanto, devido a restrições de memória, a transferência de uma alocação pode ser dividida em várias sub-transferências (ou seja, uma parte da alocação é movida do local A para B e, em seguida, a parte a seguir é movida e assim por diante, até que toda a alocação seja transferida). A primeira sub-transferência de uma alocação é marcada com o sinalizador de campo de bits TransferStart no membro Flags do membro Transfer de DXGKARG_BUILDPAGINGBUFFER; a última sub-transferência de uma alocação é marcada com o sinalizador de campo de bits TransferEnd . O driver tem a garantia de receber o fim de uma transferência pendente (ou seja, a última sub-transferência) antes que o driver receba o início de uma nova transferência.

    Cada sub-transferência pode exigir que várias chamadas para DxgkDdiBuildPagingBuffer sejam concluídas (por exemplo, o driver pode ficar sem espaço de buffer de DMA). Portanto, o driver pode receber o sinalizador TransferStart em várias chamadas para DxgkDdiBuildPagingBuffer até que o driver receba o sinalizador TransferEnd em uma chamada para DxgkDdiBuildPagingBuffer. Receber o sinalizador TransferStart várias vezes não indica o início de várias novas transferências; indica que as sub-transferências para a alocação exigem várias iterações (por exemplo, se o driver ficou sem espaço de buffer de DMA). O driver pode usar o membro MultipassOffset do DXGKARG_BUILDPAGINGBUFFER para acompanhar o progresso de uma sub-transferência específica entre várias iterações de DxgkDdiBuildPagingBuffer.

    Normalmente, uma transferência ocorre em uma única operação. Nessa situação, os sinalizadores de campo de bits TransferStart e TransferEnd são definidos.

    Em alguns cenários, o driver pode ser necessário para configurar recursos de hardware quando determinadas alocações são paginada dentro ou fora da memória. Por padrão, a GPU pode estar usando a alocação referenciada durante a chamada para DxgkDdiBuildPagingBuffer. Nesses cenários, o driver pode exigir que a alocação fique ociosa antes que o driver programe os recursos de hardware necessários (ou seja, a programação dos recursos de hardware não pode ser enfileirada no buffer de DMA fornecido). Para esses cenários, o driver pode falhar na chamada para DxgkDdiBuildPagingBuffer com STATUS_GRAPHICS_ALLOCATION_BUSY.

    Se o driver retornar STATUS_GRAPHICS_ALLOCATION_BUSY, o gerenciador de memória de vídeo aguardará até que a GPU seja concluída com qualquer referência à alocação atual e chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador de campo de bit AllocationIsIdle no membro Flags do membro Transfer de DXGKARG_BUILDPAGINGBUFFER para indicar que a alocação que está sendo referenciada está ociosa. Se o sinalizador ocioso não estiver definido, o driver sempre deverá determinar que a alocação está ocupada no momento ou pode ficar ocupada em breve. Se o sinalizador ocioso estiver definido, o gerenciador de memória de vídeo garantirá que a alocação que está sendo referenciada permaneça ociosa durante a chamada para DxgkDdiBuildPagingBuffer.

    Se o membro hAllocation de DXGKARG_BUILDPAGINGBUFFER for NULL, o driver deverá copiar os dados na origem para o destino sem executar nenhum giro ou bloco.

  • Preencher

    A operação de preenchimento preenche uma alocação com um padrão especificado. A operação de preenchimento é usada para configurar o conteúdo inicial de uma alocação. Quando o conteúdo da alocação é preenchido, a alocação é garantida como ociosa (ou seja, não em uso pela GPU). A operação de preenchimento só pode ser executada em um segmento de memória. O gerenciador de memória de vídeo nunca solicita que o driver de miniporto de exibição preencha um segmento de abertura.

  • Descartar conteúdo

    A operação de descarte de conteúdo notifica o driver de que uma alocação é descartada do local atual da alocação em um segmento de memória. Ou seja, a alocação é removida e não copiada de volta para a memória do sistema.

    Em alguns cenários, o driver pode ser necessário para configurar recursos de hardware quando determinadas alocações são paginada dentro ou fora da memória. Por padrão, a GPU pode usar a alocação referenciada durante a chamada para DxgkDdiBuildPagingBuffer. Nesses cenários, o driver pode exigir que a alocação fique ociosa antes que o driver programe os recursos de hardware necessários (ou seja, a programação dos recursos de hardware não pode ser enfileirada no buffer de DMA fornecido). Para esses cenários, o driver pode falhar na chamada para DxgkDdiBuildPagingBuffer com STATUS_GRAPHICS_ALLOCATION_BUSY.

    Se o driver retornar STATUS_GRAPHICS_ALLOCATION_BUSY, o gerenciador de memória de vídeo aguardará até que a GPU seja concluída com qualquer referência à alocação atual e chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador de campo de bit AllocationIsIdle no membro Flags do membro DiscardContent da estrutura DXGKARG_BUILDPAGINGBUFFER para indicar que a alocação que está sendo referenciada está ociosa. Se o sinalizador ocioso não estiver definido, o driver sempre deverá determinar que a alocação está ocupada no momento ou pode ficar ocupada em breve. Se o sinalizador ocioso estiver definido, o gerenciador de memória de vídeo garantirá que a alocação que está sendo referenciada permaneça ociosa durante a chamada para DxgkDdiBuildPagingBuffer.

  • Ler físico

    A operação de leitura física lê de um endereço de memória física especificado. O driver é solicitado a programar a GPU para a operação. O tamanho da memória física a ser acessada para a leitura pode ser de 1 byte a 8 bytes. Como os dados lidos são irrelevantes, DxgkDdiBuildPagingBuffer não é necessário para retornar os dados. No entanto, em cenários em que a CPU tenta ler a partir da memória do AGP após a gravação da GPU na memória do AGP, a operação de leitura-física é essencial para garantir a coerência da memória.

  • Gravar físico

    A operação write-physical é gravada em um endereço físico especificado. O driver é solicitado a programar a GPU para a operação. O tamanho da memória física a ser acessada para a operação de gravação pode ser de 1 byte a 8 bytes. Como os dados gravados são irrelevantes, DxgkDdiBuildPagingBuffer pode gravar todos os dados na memória. No entanto, em cenários em que a CPU tenta ler a partir da memória do AGP após a gravação da GPU na memória do AGP, a operação write-physical é essencial para garantir a coerência da memória.

  • Segmento de abertura de mapa

    A operação map-aperture-segment mapeia uma MDL (lista de descritores de memória) especificada em um segmento de abertura especificado em um deslocamento de segmento especificado para um número especificado de páginas. Se o sinalizador de campo de bit CacheCoherent estiver definido no membro Flags do membro MapApertureSegment da estrutura DXGKARG_BUILDPAGINGBUFFER , o driver deverá garantir que a coerência do cache seja imposta nas páginas mapeadas; caso contrário, a coerência de cache não é necessária para as páginas mapeadas.

    Nota O sinalizador cacheCoherent bit-field é definido somente quando a memória em cache está sendo mapeada em um segmento de abertura coerente de cache e nunca é definida em um segmento de abertura não coerente com cache ou em uma alocação combinada de gravação mapeada em um segmento coerente de cache.
     
    Opcionalmente, o driver pode usar MMIO (E/S mapeada por memória) para configurar um segmento de abertura. A GPU não acessará o intervalo de abertura no momento da configuração. No entanto, essa configuração de abertura não deve interferir na execução da GPU. A GPU não ficará ociosa quando DxgkDdiBuildPagingBuffer for chamado com o conjunto de tipos de operação DXGK_OPERATION_MAP_APERTURE_SEGMENT e a GPU poderá estar ocupada acessando outras partes do segmento de abertura que está sendo reconfigurado.
  • Cancelar o mapa do segmento de abertura

    A operação unmap-aperture-segment descompacta um intervalo mapeado anteriormente de um segmento de abertura especificado. O driver deve mapear o intervalo que não é mapeado para a página fictícia que o membro DummyPage do membro UnmapApertureSegment da estrutura DXGKARG_BUILDPAGINGBUFFER especifica.

    Nota Quando o driver desmarca a página fictícia, o driver deve habilitar os acessos de GPU por meio do intervalo de abertura especificado para que o subsistema de kernel de elementos gráficos DirectX possa detectar problemas de corrupção. Existem testes de conformidade para marcar essa situação.
     
    O gerenciador de memória de vídeo usa a página fictícia que está na parte não mapeada da abertura para determinar as dificuldades que o gerenciador de memória tem ao acessar o segmento de abertura.

    Opcionalmente, o driver pode usar o MMIO para configurar um segmento de abertura. A GPU não acessará o intervalo de abertura no momento da configuração. No entanto, essa configuração de abertura não deve interferir na execução da GPU. A GPU não ficará ociosa quando DxgkDdiBuildPagingBuffer for chamado com o conjunto de tipos de operação DXGK_OPERATION_UNMAP_APERTURE_SEGMENT e a GPU poderá estar ocupada acessando outras partes do segmento de abertura que está sendo reconfigurado.

  • Transferência de bloqueio especial

    A operação de transferência de bloqueio especial é semelhante à operação de transferência regular. No entanto, em vez de transferir o conteúdo da alocação de ou para o repositório de backup regular da alocação, a operação de transferência de bloqueio especial transfere o conteúdo da alocação de ou para o endereço virtual alternativo que foi configurado para a alocação quando a função pfnLockCb foi chamada com o sinalizador de campo de bit UseAlternateVA definido.

    A operação de transferência de bloqueio especial ocorre apenas em um dos seguintes cenários:

    • No momento, a alocação está acessível à CPU com um endereço virtual alternativo e está sendo removida.
    • Uma alocação que foi removida anteriormente, como a situação descrita no marcador anterior, está sendo paginada novamente.
    Os drivers que não dão suporte ao uso do sinalizador de campo de bit UseAlternateVA não serão chamados para executar uma operação de transferência de bloqueio especial.

    Em alguns cenários, o driver pode ser necessário para configurar recursos de hardware quando determinadas alocações são paginada dentro ou fora da memória. Por padrão, a GPU pode estar usando a alocação referenciada durante a chamada para DxgkDdiBuildPagingBuffer. Nesses cenários, o driver pode exigir que a alocação fique ociosa antes que o driver programe os recursos de hardware necessários (ou seja, a programação dos recursos de hardware não pode ser enfileirada no buffer de DMA fornecido). Para esses cenários, o driver pode falhar na chamada para DxgkDdiBuildPagingBuffer com STATUS_GRAPHICS_ALLOCATION_BUSY.

    Se o driver retornar STATUS_GRAPHICS_ALLOCATION_BUSY, o gerenciador de memória de vídeo aguardará até que a GPU seja concluída com qualquer referência à alocação atual e chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador de campo de bit AllocationIsIdle no membro Flags do membro SpecialLockTransfer da estrutura DXGKARG_BUILDPAGINGBUFFER para indicar que a alocação que está sendo referenciada está ociosa. Se o sinalizador ocioso não estiver definido, o driver sempre deverá determinar que a alocação está ocupada no momento ou pode ficar ocupada em breve. Se o sinalizador ocioso estiver definido, o gerenciador de memória de vídeo garantirá que a alocação que está sendo referenciada permaneça ociosa durante a chamada para DxgkDdiBuildPagingBuffer.

Observe que, se o driver precisar usar uma abertura de hardware para linearizar uma alocação deswizzled que um aplicativo pode acessar diretamente, o driver deverá desativar essa alocação enquanto o driver transfere a alocação para a memória do sistema para manter a coerência do endereço virtual da alocação. O driver deve deswizzle a alocação porque uma remoção pode ocorrer enquanto o aplicativo está acessando a alocação.

O gerenciador de memória do sistema garante que a transferência seja invisível para o aplicativo. No entanto, como a alocação está na memória do sistema e o endereço virtual da alocação não pode mais passar pela abertura de hardware, o driver deve garantir que a ordenação de bytes na memória do sistema corresponda ao que estava visível por meio da abertura.

DxgkDdiBuildPagingBuffer deve se tornar paginável.

Exemplos

O exemplo de código a seguir mostra como usar 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))

Requisitos

Requisito Valor
Cliente mínimo com suporte Windows Vista
Plataforma de Destino Área de Trabalho
Cabeçalho d3dkmddi.h
IRQL PASSIVE_LEVEL

Confira também

DXGKARG_BUILDPAGINGBUFFER

DxgkDdiAddDevice

DxgkDdiPatch

DxgkDdiSubmitCommand

pfnLockCb