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 na função MiniportDeviceContext da função DxgkDdiAddDevice.

[in/out] pBuildPagingBuffer

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

Valor de retorno

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).

Observações

A função DxgkDdiBuildPagingBuffer é chamada para criar buffers de DMA (acesso direto à memória) de finalidade especial 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 gravar a instrução de GPU (unidade de processamento gráfico) apropriada no buffer de paginação fornecido (no pDmaBuffer membro do DXGKARG_BUILDPAGINGBUFFER) de acordo com a operação de paginação solicitada; e, em seguida, o driver deve retornar o buffer de paginação para o gerenciador de memória de vídeo (que faz parte do 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.

Observação 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 (ou seja, patch) endereços físicos 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 pDmaBuffer para apontar para além do último byte gravado no buffer de paginação e retornar STATUS_SUCCESS. Como 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. 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 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 multipassOffset membro do DXGKARG_BUILDPAGINGBUFFER e pode 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 a 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 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áginas.

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 subtransmissões (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 subtransmissão de uma alocação é marcada com o sinalizador TransferStart de campo de bits no Flags membro do Transfer membro do DXGKARG_BUILDPAGINGBUFFER; a última subtransmissão de uma alocação é marcada com o sinalizador TransferEnd campo de bits. O driver tem a garantia de receber o fim de uma transferência pendente (ou seja, a última subtransmissão) antes que o driver receba o início de uma nova transferência.

    Cada subtransmissão pode exigir várias chamadas para DxgkDdiBuildPagingBuffer para concluir (por exemplo, o driver pode ficar sem espaço no 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 subtransmissões para a alocação exigem várias iterações (por exemplo, se o driver ficou sem espaço de buffer DMA). O driver pode usar o MultipassOffset membro do DXGKARG_BUILDPAGINGBUFFER para acompanhar o andamento de uma subtransposição específica entre várias iterações de DxgkDdiBuildPagingBuffer.

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

    Em alguns cenários, o driver pode ser necessário para configurar recursos de hardware quando determinadas alocações são paginados 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, em seguida, chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador AllocationIsIdle bit-field no Flags membro do Transfer membro do 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 poderá 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 hAllocation membro do DXGKARG_BUILDPAGINGBUFFER for NULL, o driver deverá copiar os dados na origem para o destino sem executar nenhum swizzling ou bloco.

  • Encher

    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 paginados 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, em seguida, chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador AllocationIsIdle bit-field no Flags membro do DiscardContent membro 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 poderá 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 da memória AGP depois que a GPU grava nessa memória AGP, a operação de leitura-física é essencial para garantir a coerência de memória.

  • Gravar físico

    A operação de gravação física é 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 da memória AGP depois que a GPU grava nessa memória AGP, a operação de gravação-física é essencial para garantir a coerência de memória.

  • Segmento de abertura de mapa

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

    Observação o sinalizador cacheCoherent somente é definido quando a memória em cache está sendo mapeada para um segmento de abertura coerente com 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 com 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.
  • Segmento de abertura não mapeado

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

    Observação Quando o driver não for mapeado para a página fictícia, o driver deve habilitar 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 verificar 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 ou para o endereço virtual alternativo que foi configurado para a alocação quando a função pfnLockCb foi chamada com o UseAlternateVA conjunto de sinalizadores de campo de bit.

    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 colocada de volta.
    Drivers que não dão suporte ao uso do UseAlternateVA sinalizador de campo de bit 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 paginados 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, em seguida, chame a função DxgkDdiBuildPagingBuffer do driver novamente. Na segunda chamada para DxgkDdiBuildPagingBuffer, o gerenciador de memória de vídeo define o sinalizador AllocationIsIdle bit-field no Flags membro do SpecialLockTransfer membro 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 poderá 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 girada 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 ficar 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
de cliente com suporte mínimo Windows Vista
da Plataforma de Destino Área de trabalho
cabeçalho d3dkmddi.h
IRQL PASSIVE_LEVEL

Consulte também

DXGKARG_BUILDPAGINGBUFFER

DxgkDdiAddDevice

DxgkDdiPatch

DxgkDdiSubmitCommand

pfnLockCb