DXGKDDI_BUILDPAGINGBUFFER función de devolución de llamada (d3dkmddi.h)

La función DxgkDdiBuildPagingBuffer compila búferes de paginación para las operaciones de memoria.

Sintaxis

DXGKDDI_BUILDPAGINGBUFFER DxgkddiBuildpagingbuffer;

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

Parámetros

[in] hAdapter

Identificador de un bloque de contexto asociado a un adaptador de pantalla. El controlador de minipuerto de pantalla proporcionó anteriormente este identificador al subsistema del kernel de gráficos de Microsoft DirectX en el parámetro de salida MiniportDeviceContext de la función DxgkDdiAddDevice .

[in/out] pBuildPagingBuffer

Puntero a una estructura DXGKARG_BUILDPAGINGBUFFER que contiene información para crear un búfer de paginación.

Valor devuelto

DxgkDdiBuildPagingBuffer devuelve uno de los siguientes valores:

Código devuelto Descripción
STATUS_SUCCESS DxgkDdiBuildPagingBuffersuccess se ha creado correctamente un búfer de paginación.
STATUS_GRAPHICS_ALLOCATION_BUSY La GPU usa actualmente la asignación para el búfer de paginación.
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER Se necesita más espacio en el búfer de paginación (es decir, en el miembro pDmaBuffer de la estructura DXGKARG_BUILDPAGINGBUFFER a la que apunta el parámetro pBuildPagingBuffer).

Comentarios

Se llama a la función DxgkDdiBuildPagingBuffer para crear búferes de acceso directo a memoria (DMA) de propósito especial que se conocen como búferes de paginación. Un búfer de paginación contiene una operación que mueve el contenido de partes de las asignaciones:

  • Dentro de un segmento de una asignación.
  • Entre segmentos de asignaciones.
  • Desde un segmento de una asignación a la memoria del sistema.
  • De la memoria del sistema a un segmento de una asignación.

El controlador de minipuerto de pantalla debe escribir la instrucción de unidad de procesamiento gráfico (GPU) adecuada en el búfer de paginación proporcionado (en el miembro pDmaBuffer de DXGKARG_BUILDPAGINGBUFFER) según la operación de paginación solicitada; y, a continuación, el controlador debe devolver el búfer de paginación al administrador de memoria de vídeo (que forma parte de Dxgkrnl.sys). El programador de GPU (que también forma parte de Dxgkrnl.sys) llama posteriormente a la función DxgkDdiSubmitCommand del controlador para solicitar que el controlador envíe el búfer de paginación como un búfer DMA normal a la GPU.

Nota Antes de que el administrador de memoria de vídeo envíe el búfer de paginación, llama a la función DxgkDdiPatch del controlador para asignar (es decir, revisión) direcciones físicas al búfer de paginación; sin embargo, en la llamada a DxgkDdiPatch, el administrador de memoria de vídeo no proporciona listas de ubicación de revisión. La función DxgkDdiPatch del controlador puede realizar actualizaciones de última hora en el búfer de paginación; sin embargo, la función DxgkDdiPatch del controlador no puede cambiar el tamaño del búfer de paginación.
 
Cuando el controlador compila correctamente el búfer de paginación, dxgkDdiBuildPagingBuffer del controlador debe actualizar pDmaBuffer para que apunte más allá del último byte que se escribe en el búfer de paginación y, a continuación, devolver STATUS_SUCCESS. Dado que DxgkDdiBuildPagingBuffer solo puede producir un error si se queda sin espacio en el búfer de paginación, el controlador siempre debe comprobar que el búfer de paginación tiene suficiente espacio restante antes de escribir en el búfer. Si no hay suficiente espacio en el búfer de paginación, el controlador debe devolver STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER. Después, el administrador de memoria de vídeo adquiriría un nuevo búfer de paginación y llamaría de nuevo a la función DxgkDdiBuildPagingBuffer del controlador para rellenar el nuevo búfer de paginación según la operación de paginación solicitada. Tenga en cuenta que, para una operación de paginación solicitada determinada que rellena varios búferes de paginación, el programador llama a la función DxgkDdiSubmitCommand del controlador varias veces para que cada búfer de paginación parcial envíe cada búfer de forma independiente.

Si DxgkDdiBuildPagingBuffer determina que una operación de paginación requiere más de un búfer de paginación, el controlador puede especificar información en el miembro MultipassOffset de DXGKARG_BUILDPAGINGBUFFER y puede usar esta información en varias iteraciones de la operación de paginación. El administrador de memoria de vídeo inicializa la información de MultipassOffset en cero antes de la primera solicitud de operación de paginación y no modifica la información de MultipassOffset entre iteraciones. Por lo tanto, el controlador puede usar MultipassOffset para guardar el progreso entre iteraciones. Por ejemplo, el controlador puede almacenar el número de página que se transfirió por última vez para una transferencia basada en páginas.

Actualmente se crea un búfer de paginación para los siguientes tipos de operaciones:

  • Transferencia

    La operación de transferencia mueve el contenido de una asignación de una ubicación a otra. Esta operación es el tipo más común de operación de memoria.

    Una asignación siempre se transfiere completamente de una ubicación a otra. Sin embargo, debido a las restricciones de memoria, la transferencia de una asignación se puede dividir en varias sub-transferencias (es decir, una parte de la asignación se mueve de la ubicación A a B y, a continuación, se mueve la siguiente parte, etc., hasta que se transfiere toda la asignación). La primera sub-transferencia de una asignación se marca con la marca de campo de bits TransferStart en el miembro Flags del miembro Transfer de DXGKARG_BUILDPAGINGBUFFER; la última sub-transferencia de una asignación se marca con la marca transferEnd de campo de bits. Se garantiza que el conductor reciba el final de una transferencia pendiente (es decir, la última subinferencia) antes de que el controlador reciba el inicio de una nueva transferencia.

    Cada sub-transferencia puede requerir varias llamadas a DxgkDdiBuildPagingBuffer para completarse (por ejemplo, el controlador podría estar sin espacio de búfer DMA). Por lo tanto, el controlador puede recibir la marca TransferStart en varias llamadas a DxgkDdiBuildPagingBuffer hasta que el controlador reciba la marca TransferEnd en una llamada a DxgkDdiBuildPagingBuffer. La recepción de la marca TransferStart varias veces no indica el inicio de varias transferencias nuevas; indica que las sub-transferencias de la asignación requieren varias iteraciones (por ejemplo, si el controlador se quedó sin espacio de búfer DMA). El controlador puede usar el miembro MultipassOffset de DXGKARG_BUILDPAGINGBUFFER para realizar un seguimiento del progreso de una sub-transferencia determinada en varias iteraciones de DxgkDdiBuildPagingBuffer.

    Normalmente, una transferencia se produce en una sola operación. En esta situación, se establecen las marcas de campo de bits TransferStart y TransferEnd .

    En algunos escenarios, es posible que sea necesario que el controlador configure recursos de hardware cuando determinadas asignaciones se paginan en la memoria o en la memoria insuficiente. De forma predeterminada, la GPU podría usar la asignación a la que se hace referencia durante la llamada a DxgkDdiBuildPagingBuffer. En estos escenarios, es posible que el controlador requiera que la asignación esté inactiva antes de que el controlador programe los recursos de hardware necesarios (es decir, la programación de los recursos de hardware no se puede poner en cola en el búfer DMA proporcionado). En estos escenarios, el controlador puede producir un error en la llamada a DxgkDdiBuildPagingBuffer con STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si el controlador devuelve STATUS_GRAPHICS_ALLOCATION_BUSY, el administrador de memoria de vídeo espera hasta que la GPU se realiza con cualquier referencia a la asignación actual y, a continuación, vuelve a llamar a la función DxgkDdiBuildPagingBuffer del controlador. En la segunda llamada a DxgkDdiBuildPagingBuffer, el administrador de memoria de vídeo establece la marca de campo de bits AllocationIsIdle en el miembro Flags del miembro Transfer de DXGKARG_BUILDPAGINGBUFFER para indicar que la asignación a la que se hace referencia está inactiva. Si no se establece la marca de inactividad, el controlador siempre debe determinar que la asignación está ocupada actualmente o que puede estar ocupada pronto. Si se establece la marca de inactividad, el administrador de memoria de vídeo garantiza que la asignación a la que se hace referencia permanece inactiva mientras dure la llamada a DxgkDdiBuildPagingBuffer.

    Si el miembro hAllocation de DXGKARG_BUILDPAGINGBUFFER es NULL, el controlador debe copiar los datos del origen en el destino sin realizar ninguna rotación o mosaico.

  • Rellenar

    La operación de relleno rellena una asignación con un patrón especificado. La operación de relleno se usa para configurar el contenido inicial de una asignación. Cuando se rellena el contenido de la asignación, se garantiza que la asignación está inactiva (es decir, no está en uso por la GPU). La operación de relleno solo se puede realizar en un segmento de memoria. El administrador de memoria de vídeo nunca solicita que el controlador de miniporte de pantalla rellene un segmento de apertura.

  • Descartar contenido

    La operación de descartar contenido notifica al controlador que se descarta una asignación de la ubicación actual de la asignación en un segmento de memoria. Es decir, la asignación se expulsa y no se copia en la memoria del sistema.

    En algunos escenarios, es posible que sea necesario que el controlador configure recursos de hardware cuando determinadas asignaciones se paginan en la memoria o en la memoria insuficiente. De forma predeterminada, la GPU podría usar la asignación a la que se hace referencia durante la llamada a DxgkDdiBuildPagingBuffer. En estos escenarios, es posible que el controlador requiera que la asignación esté inactiva antes de que el controlador programe los recursos de hardware necesarios (es decir, la programación de los recursos de hardware no se puede poner en cola en el búfer DMA proporcionado). En estos escenarios, el controlador puede producir un error en la llamada a DxgkDdiBuildPagingBuffer con STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si el controlador devuelve STATUS_GRAPHICS_ALLOCATION_BUSY, el administrador de memoria de vídeo espera hasta que la GPU se realiza con cualquier referencia a la asignación actual y, a continuación, vuelve a llamar a la función DxgkDdiBuildPagingBuffer del controlador. En la segunda llamada a DxgkDdiBuildPagingBuffer, el administrador de memoria de vídeo establece la marca de campo de bits AllocationIsIdle en el miembro Flags del miembro DiscardContent de la estructura DXGKARG_BUILDPAGINGBUFFER para indicar que la asignación a la que se hace referencia está inactiva. Si no se establece la marca de inactividad, el controlador siempre debe determinar que la asignación está ocupada actualmente o que puede estar ocupada pronto. Si se establece la marca de inactividad, el administrador de memoria de vídeo garantiza que la asignación a la que se hace referencia permanece inactiva mientras dure la llamada a DxgkDdiBuildPagingBuffer.

  • Lectura física

    La operación de lectura física lee desde una dirección de memoria física especificada. Se solicita al controlador que programe la GPU para la operación. El tamaño de la memoria física a la que acceder para la lectura puede ser de 1 byte a 8 bytes. Dado que los datos que se leen son irrelevantes, DxgkDdiBuildPagingBuffer no es necesario para devolver los datos. Sin embargo, en escenarios en los que la CPU intenta leer de la memoria AGP después de que la GPU escribe en esa memoria de AGP, la operación de lectura física es fundamental para garantizar la coherencia de memoria.

  • Escritura física

    La operación de escritura física escribe en una dirección física especificada. Se solicita al controlador que programe la GPU para la operación. El tamaño de la memoria física a la que se va a acceder para la operación de escritura puede ser de 1 byte a 8 bytes. Dado que los datos escritos son irrelevantes, DxgkDdiBuildPagingBuffer puede escribir cualquier dato en la memoria. Sin embargo, en escenarios en los que la CPU intenta leer de la memoria AGP después de que la GPU escribe en esa memoria AGP, la operación física de escritura es fundamental para garantizar la coherencia de memoria.

  • Segmento de apertura del mapa

    La operación map-aperture-segment asigna una lista de descriptores de memoria (MDL) especificada a un segmento de apertura especificado en un desplazamiento de segmento especificado para un número especificado de páginas. Si la marca de campo de bits CacheCoherent está establecida en el miembro Flags del miembro MapApertureSegment de la estructura DXGKARG_BUILDPAGINGBUFFER , el controlador debe asegurarse de que la coherencia de caché se aplica en las páginas asignadas; de lo contrario, la coherencia de caché no es necesaria para las páginas asignadas.

    Nota La marca de campo de bits CacheCoherent solo se establece cuando se asigna memoria caché a un segmento de apertura coherente con caché y nunca se establece en un segmento de apertura coherente con caché o en una asignación combinada de escritura asignada a un segmento coherente con caché.
     
    Opcionalmente, el controlador puede usar E/S asignada a memoria (MMIO) para configurar un segmento de apertura. La GPU no accederá al intervalo de apertura en el momento de la configuración. Sin embargo, esta configuración de apertura no debe interferir con la ejecución de la GPU. La GPU no estará inactiva cuando se llame a DxgkDdiBuildPagingBuffer con el tipo de operación DXGK_OPERATION_MAP_APERTURE_SEGMENT establecido y la GPU podría estar ocupada accediendo a otras partes del segmento de apertura que se está reconfigurando.
  • Desasignación del segmento de apertura

    La operación de unmap-aperture-segment desasigna un rango asignado previamente de un segmento de apertura especificado. El controlador debe asignar el intervalo que no está asignado a la página ficticia que especifica el miembro DummyPage del miembro UnmapApertureSegment de la estructura DXGKARG_BUILDPAGINGBUFFER .

    Nota Cuando el controlador desasignación a la página ficticia, el controlador debe habilitar el acceso de GPU a través del intervalo de apertura especificado para que el subsistema del kernel de gráficos de DirectX pueda detectar problemas de daños. Existen pruebas de conformidad para comprobar esta situación.
     
    El administrador de memoria de vídeo usa la página ficticia que se encuentra en la parte no asignada de la apertura para determinar las dificultades que tiene el administrador de memoria al acceder al segmento de apertura.

    Opcionalmente, el controlador puede usar MMIO para configurar un segmento de apertura. La GPU no accederá al intervalo de apertura en el momento de la configuración. Sin embargo, esta configuración de apertura no debe interferir con la ejecución de la GPU. La GPU no estará inactiva cuando se llame a DxgkDdiBuildPagingBuffer con el tipo de operación DXGK_OPERATION_UNMAP_APERTURE_SEGMENT establecido y la GPU podría estar ocupada accediendo a otras partes del segmento de apertura que se está reconfigurando.

  • Transferencia de bloqueo especial

    La operación especial de transferencia de bloqueo es similar a la operación de transferencia normal. Sin embargo, en lugar de transferir el contenido de la asignación desde o al almacén de respaldo normal de la asignación, la operación especial de transferencia de bloqueo transfiere el contenido de la asignación desde o a la dirección virtual alternativa que se configuró para la asignación cuando se llamó a la función pfnLockCb con el conjunto de marcas de campo de bits UseAlternateVA .

    La operación especial de transferencia de bloqueo solo se produce en uno de los escenarios siguientes:

    • Actualmente, la asignación es accesible para la CPU con una dirección virtual alternativa y se está expulsando.
    • Una asignación que se expulsó anteriormente, como la situación descrita en la viñeta anterior, se vuelve a paginar.
    No se llamará a los controladores que no admiten el uso de la marca de campo de bits UseAlternateVA para realizar una operación especial de transferencia de bloqueo.

    En algunos escenarios, es posible que sea necesario que el controlador configure los recursos de hardware cuando determinadas asignaciones se paginan en la memoria o fuera de la memoria. De forma predeterminada, la GPU podría usar la asignación a la que se hace referencia durante la llamada a DxgkDdiBuildPagingBuffer. En estos escenarios, el controlador podría requerir que la asignación esté inactiva antes de que el controlador programe los recursos de hardware necesarios (es decir, la programación de los recursos de hardware no se puede poner en cola en el búfer DMA proporcionado). En estos escenarios, el controlador puede producir un error en la llamada a DxgkDdiBuildPagingBuffer con STATUS_GRAPHICS_ALLOCATION_BUSY.

    Si el controlador devuelve STATUS_GRAPHICS_ALLOCATION_BUSY, el administrador de memoria de vídeo espera hasta que la GPU se realice con cualquier referencia a la asignación actual y, a continuación, vuelva a llamar a la función DxgkDdiBuildPagingBuffer del controlador. En la segunda llamada a DxgkDdiBuildPagingBuffer, el administrador de memoria de vídeo establece la marca de campo de bits AllocationIsIdle en el miembro Flags del miembro SpecialLockTransfer de la estructura DXGKARG_BUILDPAGINGBUFFER para indicar que la asignación a la que se hace referencia está inactiva. Si no se establece la marca de inactividad, el controlador siempre debe determinar que la asignación está ocupada actualmente o puede que pronto esté ocupada. Si se establece la marca de inactividad, el administrador de memoria de vídeo garantiza que la asignación a la que se hace referencia permanece inactiva durante la llamada a DxgkDdiBuildPagingBuffer.

Tenga en cuenta que si el controlador debe usar una apertura de hardware para linealizar una asignación a la que una aplicación puede acceder directamente, el controlador debe desenredar esa asignación mientras el controlador transfiere la asignación a la memoria del sistema para mantener la coherencia de la dirección virtual de la asignación. El controlador debe desenlajar la asignación porque se puede producir una expulsión mientras la aplicación accede a la asignación.

El administrador de memoria del sistema garantiza que la transferencia sea invisible para la aplicación. Sin embargo, dado que la asignación está en memoria del sistema y la dirección virtual de la asignación ya no puede pasar por la apertura del hardware, el controlador debe asegurarse de que el orden de bytes en la memoria del sistema coincida con lo que era visible a través de la apertura.

DxgkDdiBuildPagingBuffer debe ser paginable.

Ejemplos

En el ejemplo de código siguiente se muestra cómo 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 Value
Cliente mínimo compatible Windows Vista
Plataforma de destino Escritorio
Encabezado d3dkmddi.h
IRQL PASSIVE_LEVEL

Consulte también

DXGKARG_BUILDPAGINGBUFFER

DxgkDdiAddDevice

DxgkDdiPatch

DxgkDdiSubmitCommand

pfnLockCb