функция обратного вызова DXGKDDI_BUILDPAGINGBUFFER (d3dkmddi.h)

Функция DxgkDdiBuildPagingBuffer создает буферы подкачки для операций с памятью.

Синтаксис

DXGKDDI_BUILDPAGINGBUFFER DxgkddiBuildpagingbuffer;

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

Параметры

[in] hAdapter

Дескриптор для блока контекста, связанного с видеоадаптером. Драйвер мини-порта дисплея ранее предоставлял этот дескриптор подсистеме ядра графики Microsoft DirectX в выходном параметре MiniportDeviceContext функции DxgkDdiAddDevice .

[in/out] pBuildPagingBuffer

Указатель на структуру DXGKARG_BUILDPAGINGBUFFER , содержащую сведения о создании буфера подкачки.

Возвращаемое значение

DxgkDdiBuildPagingBuffer возвращает одно из следующих значений:

Код возврата Описание
STATUS_SUCCESS DxgkDdiBuildPagingBuffersuccessful создал буфер подкачки.
STATUS_GRAPHICS_ALLOCATION_BUSY В настоящее время GPU использует выделение для буфера подкачки.
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER В буфере подкачки (то есть в элементе pDmaBuffer структуры DXGKARG_BUILDPAGINGBUFFER , на которую указывает параметр pBuildPagingBuffer, требуется больше места).

Комментарии

Функция DxgkDdiBuildPagingBuffer вызывается для создания специальных буферов прямого доступа к памяти (DMA), которые называются буферами подкачки. Буфер подкачки содержит операцию, которая перемещает содержимое частей выделений:

  • В сегменте выделения.
  • Между сегментами выделений.
  • Из сегмента выделения в системную память.
  • От системной памяти к сегменту выделения.

Драйвер мини-порта дисплея должен записать соответствующую инструкцию графического процессора (GPU) в предоставленный буфер подкачки (в элементе pDmaBufferDXGKARG_BUILDPAGINGBUFFER) в соответствии с запрошенной операцией разбиения по страницам; а затем драйвер должен вернуть буфер подкачки обратно в диспетчер видеопамять (который является частью Dxgkrnl.sys). Планировщик GPU (который также входит в составDxgkrnl.sys) впоследствии вызывает функцию DxgkDdiSubmitCommand драйвера, чтобы запросить отправку драйвером буфера подкачки в качестве обычного буфера DMA в GPU.

Примечание Прежде чем диспетчер видеопаметь отправляет буфер подкачки, он вызывает функцию DxgkDdiPatch драйвера для назначения (т. е. исправления) физических адресов буферу подкачки; Однако при вызове DxgkDdiPatch диспетчер видеопамяти не предоставляет списки расположения исправлений. Функция DxgkDdiPatch драйвера может выполнять обновления буфера подкачки в последнюю минуту; Однако функция DxgkDdiPatch драйвера не может изменить размер буфера подкачки.
 
Когда драйвер успешно создает буфер подкачки, dxgkDdiBuildPagingBuffer драйвера должен обновить pDmaBuffer , чтобы указать последний байт, записанный в буфер подкачки, а затем вернуть STATUS_SUCCESS. Так как DxgkDdiBuildPagingBuffer может завершиться ошибкой только в том случае, если в буфере подкачки не хватает места, драйвер должен всегда проверять, что буфер подкачки имеет достаточно места, оставшегося перед записью в буфер. Если в буфере подкачки остается недостаточно места, драйвер должен вернуть STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER. Затем диспетчер видеопамяти получит новый буфер подкачки и снова вызовет функцию DxgkDdiBuildPagingBuffer драйвера, чтобы заполнить новый буфер подкачки в соответствии с запрошенной операцией разбиения на страницы. Обратите внимание, что для заданной операции разбиения по страницам, которая заполняет несколько буферов разбиения по страницам, планировщик несколько раз вызывает функцию DxgkDdiSubmitCommand драйвера для каждого частичного буфера подкачки, чтобы отправить каждый буфер независимо.

Если DxgkDdiBuildPagingBuffer определяет, что для операции разбиения по страницам требуется несколько буферов подкачки, драйвер может указать сведения в элементе MultipassOffsetDXGKARG_BUILDPAGINGBUFFER и может использовать эти сведения в нескольких итерациях операции разбиения по страницам. Диспетчер видеопаметь инициализирует сведения в MultipassOffset до нуля перед первым запросом операции разбиения по страницам и не изменяет данные в MultipassOffset между итерациями. Поэтому драйвер может использовать MultipassOffset для сохранения хода выполнения между итерациями. Например, драйвер может хранить номер страницы, который последний раз был передан для передачи на основе страниц.

Буфер подкачки в настоящее время создается для следующих типов операций:

  • Перенос

    Операция переноса перемещает содержимое выделения из одного расположения в другое. Эта операция является наиболее распространенным типом операций с памятью.

    Выделение всегда полностью переносится из одного расположения в другое. Однако из-за ограничений памяти передачу выделения можно разделить на несколько вложенных передач (т. е. часть выделения перемещается из расположения A в B, а затем следующая часть перемещается и т. д., пока не будет перенесено все выделение). Первая вложенная передача выделения помечается флагом битового поля TransferStart в элементе Flags элемента Transfer DXGKARG_BUILDPAGINGBUFFER; последняя подпередача выделения помечается флагом битового поля TransferEnd . Драйвер гарантированно получит окончание ожидающей передачи (т. е. последней подперед) до того, как драйвер получит начало новой передачи.

    Для выполнения каждой вложенной передачи может потребоваться несколько вызовов DxgkDdiBuildPagingBuffer (например, в драйвере может закончиться буфер DMA). Таким образом, драйвер может получить флаг TransferStart в нескольких вызовах DxgkDdiBuildPagingBuffer , пока драйвер не получит флаг TransferEnd в вызове DxgkDdiBuildPagingBuffer. Получение флага TransferStart несколько раз не указывает на начало нескольких новых передач; оно указывает, что вложенные передачи для выделения требуют нескольких итераций (например, если в драйвере не было места в буфере DMA). Драйвер может использовать элемент MultipassOffsetDXGKARG_BUILDPAGINGBUFFER для отслеживания хода выполнения определенной подпередажи через несколько итераций DxgkDdiBuildPagingBuffer.

    Как правило, передача выполняется в рамках одной операции. В этом случае устанавливаются флаги битовых полей TransferStart и TransferEnd .

    В некоторых сценариях драйвер может потребоваться для настройки аппаратных ресурсов, когда определенные выделения выстраивается в памяти или из нее. По умолчанию GPU может использовать выделение, на которое ссылается во время вызова DxgkDdiBuildPagingBuffer. В таких сценариях драйвер может потребовать, чтобы выделение было бездействующим, прежде чем драйвер запрограммирует необходимые аппаратные ресурсы (то есть программирование аппаратных ресурсов не может быть помещено в очередь в предоставленный буфер DMA). В таких сценариях драйвер может завершить вызов DxgkDdiBuildPagingBuffer с STATUS_GRAPHICS_ALLOCATION_BUSY.

    Если драйвер возвращает STATUS_GRAPHICS_ALLOCATION_BUSY, диспетчер видеопамоты ожидает завершения работы GPU с любой ссылкой на текущее выделение, а затем снова вызывает функцию DxgkDdiBuildPagingBuffer драйвера. Во втором вызове DxgkDdiBuildPagingBuffer диспетчер видеопамяти устанавливает флаг битового поля AllocationIsIdle в элементе Flags элемента Transfer DXGKARG_BUILDPAGINGBUFFER, чтобы указать, что выделение, на которое ссылается ссылка, неактивно. Если флаг простоя не установлен, драйвер всегда должен определить, что выделение занято в данный момент или вскоре может стать занято. Если установлен флаг простоя, диспетчер видеопамяти гарантирует, что выделение, на которое ссылается ссылка, остается бездействующим в течение всего вызова DxgkDdiBuildPagingBuffer.

    Если элемент hAllocation DXGKARG_BUILDPAGINGBUFFER имеет значение NULL, драйвер должен скопировать данные из источника в место назначения, не выполняя никаких поворотов или мозаиков.

  • Заполнить

    Операция заполнения заполняет выделение указанным шаблоном. Операция заполнения используется для настройки начального содержимого выделения. При заполнении содержимого выделения выделение гарантированно будет бездействующим (т. е. не используется GPU). Операцию заполнения можно выполнить только в сегменте памяти. Диспетчер видеопамоты никогда не запрашивает, чтобы драйвер минипорта дисплея заполнял сегмент диафрагмы.

  • Удалить содержимое

    Операция удаления содержимого уведомляет драйвер о том, что выделение удаляется из текущего расположения выделения в сегменте памяти. То есть выделение вытеснится и не копируется обратно в системную память.

    В некоторых сценариях драйвер может потребоваться для настройки аппаратных ресурсов, когда определенные выделения выстраивается в памяти или из нее. По умолчанию GPU может использовать выделение, на которое ссылается во время вызова DxgkDdiBuildPagingBuffer. В таких сценариях драйвер может потребовать, чтобы выделение было бездействующим, прежде чем драйвер запрограммирует необходимые аппаратные ресурсы (то есть программирование аппаратных ресурсов не может быть помещено в очередь в предоставленный буфер DMA). В таких сценариях драйвер может завершить вызов DxgkDdiBuildPagingBuffer с STATUS_GRAPHICS_ALLOCATION_BUSY.

    Если драйвер возвращает STATUS_GRAPHICS_ALLOCATION_BUSY, диспетчер видеопамоты ожидает завершения работы GPU с любой ссылкой на текущее выделение, а затем снова вызывает функцию DxgkDdiBuildPagingBuffer драйвера. Во втором вызове DxgkDdiBuildPagingBuffer диспетчер видеопамяти устанавливает флаг битового поля AllocationIsIdle в элементе Flags элемента DiscardContent структуры DXGKARG_BUILDPAGINGBUFFER , чтобы указать, что выделение, на которое ссылается ссылка, неактивно. Если флаг простоя не установлен, драйвер всегда должен определить, что выделение занято в данный момент или вскоре может стать занято. Если установлен флаг простоя, диспетчер видеопамяти гарантирует, что выделение, на которое ссылается ссылка, остается бездействующим в течение всего вызова DxgkDdiBuildPagingBuffer.

  • Чтение физического

    Физическая операция чтения считывает данные из указанного адреса физической памяти. Драйвер запрашивается для программирования GPU для операции. Размер физической памяти для чтения может составлять от 1 байта до 8 байт. Так как считываемые данные не имеют значения, DxgkDdiBuildPagingBuffer не требуется для возврата данных. Однако в сценариях, когда ЦП пытается считывать данные из памяти AGP после записи GPU в эту память AGP, физическая операция чтения имеет решающее значение для обеспечения когерентности памяти.

  • Запись физического

    Физическая операция записи выполняет запись на указанный физический адрес. Драйвер запрашивается для программирования GPU для операции. Размер физической памяти для доступа к операции записи может составлять от 1 байта до 8 байт. Так как записанные данные не имеют значения, DxgkDdiBuildPagingBuffer может записывать любые данные в память. Однако в сценариях, когда ЦП пытается считывать данные из памяти AGP после записи GPU в эту память AGP, физическая операция записи имеет решающее значение для обеспечения совместного использования памяти.

  • Сегмент апертуры карты

    Операция map-aperture-segment сопоставляет указанный список дескрипторов памяти (MDL) с указанным сегментом диафрагмы с указанным смещением сегмента для указанного количества страниц. Если флаг битового поля CacheCoherent установлен в элементе Flags элемента MapApertureSegment структуры DXGKARG_BUILDPAGINGBUFFER , драйвер должен убедиться, что на сопоставленных страницах применяется когерентность кэша; В противном случае для сопоставленных страниц не требуется совместное кэширование.

    Примечание Флаг битового поля CacheCoherent устанавливается только в том случае, если кэшируемая память сопоставляется с сегментом апертуры, когерентной кэшем, и никогда не устанавливается на сегменте несогласованного с кэшем диафрагмы или в объединенном выделении записи, сопоставленном с сегментом, когерентным кэшем.
     
    При необходимости драйвер может использовать сопоставленные в памяти операции ввода-вывода (MMIO) для настройки сегмента диафрагмы. GPU не будет обращаться к диапазону диафрагмы во время настройки. Однако такая конфигурация диафрагмы не должна мешать выполнению GPU. GPU не будет бездействующим при вызове DxgkDdiBuildPagingBuffer с DXGK_OPERATION_MAP_APERTURE_SEGMENT типом операции, а GPU может быть занят доступом к другим частям сегмента диафрагмы, который настраивается.
  • Отмена сопоставления сегмента диафрагмы

    Операция unmap-aperture-segment отменяет сопоставление ранее сопоставленного диапазона указанного сегмента диафрагмы. Драйвер должен сопоставить диапазон, который не сопоставляется с фиктивной страницей, указанной элементом DummyPage члена UnmapApertureSegmentструктуры DXGKARG_BUILDPAGINGBUFFER .

    Примечание Когда драйвер отменяет сопоставление с фиктивной страницей, драйвер должен включить доступ к GPU через указанный диапазон диафрагмы, чтобы подсистема графического ядра DirectX могла обнаружить проблемы с повреждением. Для проверка этой ситуации существуют тесты соответствия.
     
    Диспетчер видеопамяли использует фиктивную страницу, которая находится в несопоставленной части диафрагмы, чтобы определить трудности, с которыми диспетчер памяти обращается к сегменту диафрагмы.

    Драйвер может при необходимости использовать MMIO для настройки сегмента диафрагмы. GPU не будет обращаться к диапазону диафрагмы во время настройки. Однако такая конфигурация диафрагмы не должна мешать выполнению GPU. GPU не будет бездействующим при вызове DxgkDdiBuildPagingBuffer с DXGK_OPERATION_UNMAP_APERTURE_SEGMENT типом операции, а GPU может быть занят доступом к другим частям сегмента диафрагмы, который перенастраивается.

  • Специальная блокировка передачи

    Операция специальной блокировки и передачи аналогична обычной операции передачи. Однако вместо передачи содержимого выделения из регулярного резервного хранилища выделения или в него операция специальной блокировки и передачи передает содержимое выделения с или на альтернативный виртуальный адрес, настроенный для выделения при вызове функции pfnLockCb с установленным флагом битового поля UseAlternateVA .

    Операция специальной блокировки и передачи выполняется только в одном из следующих сценариев:

    • Выделение в настоящее время доступно ЦП с альтернативным виртуальным адресом и вытеснается.
    • Выделение, которое было ранее вытеснило, например ситуация, описанная в предыдущем маркере, возвращается обратно.
    Драйверы, которые не поддерживают использование флага битового поля UseAlternateVA , не будут вызываться для выполнения специальной операции блокировки и передачи.

    В некоторых сценариях драйвер может потребоваться для настройки аппаратных ресурсов, когда определенные выделения размещаются в памяти или из нее. По умолчанию GPU может использовать выделение, на которое ссылается во время вызова DxgkDdiBuildPagingBuffer. В таких сценариях драйвер может потребовать, чтобы выделение не было в состоянии простоя, прежде чем драйвер запрограммирует необходимые аппаратные ресурсы (то есть программирование аппаратных ресурсов не может быть помещено в очередь в предоставленный буфер DMA). В таких сценариях драйвер может завершить вызов DxgkDdiBuildPagingBuffer с STATUS_GRAPHICS_ALLOCATION_BUSY.

    Если драйвер возвращает STATUS_GRAPHICS_ALLOCATION_BUSY, диспетчер видеопамятки ожидает завершения работы GPU с любой ссылкой на текущее выделение, а затем снова вызывает функцию DxgkDdiBuildPagingBuffer драйвера. Во втором вызове DxgkDdiBuildPagingBuffer диспетчер видеопамяти устанавливает флаг битового поля AllocationIsIdle в элементе Flags элемента SpecialLockTransfer структуры DXGKARG_BUILDPAGINGBUFFER , чтобы указать, что выделение, на которое ссылается ссылка, бездействует. Если флаг простоя не установлен, драйвер всегда должен определять, что выделение либо занято в данный момент, либо может скоро стать занятым. Если установлен флаг простоя, диспетчер видеопамяти гарантирует, что выделение, на которое ссылается ссылка, остается бездействующим в течение всего вызова DxgkDdiBuildPagingBuffer.

Обратите внимание, что если драйвер должен использовать аппаратную диафрагму для линейного выделения, к которому приложение может получить прямой доступ, драйвер должен отменить это выделение, в то время как драйвер передает выделение в системную память для поддержания когерентности виртуального адреса выделения. Драйвер должен отменить выделение, так как может произойти вытеснение, когда приложение обращается к выделению.

Системный диспетчер памяти гарантирует, что передача невидима для приложения. Однако, поскольку выделение находится в системной памяти, а виртуальный адрес выделения больше не может проходить через аппаратную диафрагму, драйвер должен убедиться, что порядок байтов в системной памяти соответствует тому, что было видно через диафрагму.

DxgkDdiBuildPagingBuffer должен быть доступным для страниц.

Примеры

В следующем примере кода показано, как использовать 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))

Требования

Требование Значение
Минимальная версия клиента Windows Vista
Целевая платформа Персональный компьютер
Верхняя часть d3dkmddi.h
IRQL PASSIVE_LEVEL

См. также раздел

DXGKARG_BUILDPAGINGBUFFER

DxgkDdiAddDevice

DxgkDdiPatch

DxgkDdiSubmitCommand

pfnLockCb