DXGKDDI_BUILDPAGINGBUFFER回呼函式 (d3dkmddi.h)

DxgkDdiBuildPagingBuffer 函式會建置記憶體作業的分頁緩衝區。

語法

DXGKDDI_BUILDPAGINGBUFFER DxgkddiBuildpagingbuffer;

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

參數

[in] hAdapter

與顯示配接器相關聯的內容區塊句柄。 顯示迷你埠驅動程式先前已將此句柄提供給 DxgkDdiAddDevice 函式之 MiniportDeviceContext 輸出參數中的 Microsoft DirectX 圖形核心子系統。

[in/out] pBuildPagingBuffer

DXGKARG_BUILDPAGINGBUFFER 結構的指標,其中包含建置分頁緩衝區的資訊。

傳回值

DxgkDdiBuildPagingBuffer 會傳回下列其中一個值:

傳回碼 描述
STATUS_SUCCESS DxgkDdiBuildPagingBuffersuccessful 建置分頁緩衝區。
STATUS_GRAPHICS_ALLOCATION_BUSY GPU 目前正在使用分頁緩衝區的配置。
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER 分頁緩衝區 (需要更多空間,也就是 pBuildPagingBuffer 參數指向 ) 之DXGKARG_BUILDPAGINGBUFFER 結構的 pDmaBuffer 成員。

備註

會呼叫 DxgkDdiBuildPagingBuffer 函式來建置特殊用途的直接記憶體存取, (稱為分頁緩衝區的 DMA) 緩衝區。 分頁緩衝區包含可移動配置部分內容的作業:

  • 在配置區段內。
  • 配置區段之間。
  • 從配置區段到系統記憶體。
  • 從系統記憶體到配置區段。

顯示迷你埠驅動程序必須根據要求的分頁作業,在提供的分頁緩衝區 (中,撰寫適當的圖形處理器 (GPU) 指令,DXGKARG_BUILDPAGINGBUFFER) 的 pDmaBuffer 成員;然後驅動程式必須將分頁緩衝區傳回影片記憶體管理員 (,這是 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 判斷分頁作業需要多個分頁緩衝區,驅動程式可以在DXGKARG_BUILDPAGINGBUFFERMultipassOffset 成員中指定資訊,而且可以在分頁作業的多個反覆專案中使用此資訊。 視訊記憶體管理員會在第一個分頁作業要求之前,將 MultipassOffset 中的資訊初始化為零,而且不會在反覆項目之間修改 MultipassOffset 中的資訊。 因此,驅動程式可以使用 MultipassOffset 來儲存反覆專案之間的進度。 例如,驅動程式可以儲存上次針對分頁型傳輸傳送的頁碼。

目前已針對下列類型的作業建置分頁緩衝區:

  • 傳輸

    傳輸作業會將配置的內容從一個位置移到另一個位置。 此作業是最常見的記憶體作業類型。

    配置一律會從某個位置完全傳輸到另一個位置。 不過,由於記憶體限制,配置傳輸可以分割成多個子傳輸 (也就是說,配置的部分會從位置 A 移至 B,然後移動下列部分,依此類移,直到傳輸整個配置) 為止。 配置的第一個子傳輸會標示為 TransferStart 位字段旗標,該旗標位於 DXGKARG_BUILDPAGINGBUFFER 之 Transfer 成員的 Flags 成員中;配置的最後一次子傳輸會標示為 TransferEnd 位字段旗標。 驅動程序保證會接收暫止傳輸的結尾 (,也就是驅動程式收到新傳輸開始之前的最後一次子傳輸) 。

    每個子傳輸可能需要多次呼叫 DxgkDdiBuildPagingBuffer 來完成 (例如,驅動程式可能會用盡 DMA 緩衝區空間) 。 因此,驅動程式可能會在多次呼叫 DxgkDdiBuildPagingBuffer 時收到 TransferStart 旗標,直到驅動程式在呼叫 DxgkDdiBuildPagingBuffer 時收到 TransferEnd 旗標為止。 收到 TransferStart 旗標多次並不表示多個新傳輸的開始;它表示配置子傳輸需要多個反覆專案 (例如,如果驅動程式用完 DMA 緩衝區空間) 。 驅動程式可以使用 DXGKARG_BUILDPAGINGBUFFERMultipassOffset 成員,在 DxgkDdiBuildPagingBuffer 的多個反覆專案之間追蹤特定子傳輸的進度。

    一般而言,傳輸會在單一作業中發生。 在此情況下,會設定 TransferStartTransferEnd 位欄位旗標。

    在某些情況下,當特定配置分頁或記憶體不足時,可能需要驅動程式來設定硬體資源。 根據預設,GPU 可能會使用呼叫 DxgkDdiBuildPagingBuffer 期間所參考的配置。 在這些情況下,驅動程式可能需要配置閑置,驅動程式才能 (程式設計所需的硬體資源,也就是程式設計硬體資源無法在提供的 DMA 緩衝區) 中排入佇列。 在這種情況下,驅動程式可能會因為STATUS_GRAPHICS_ALLOCATION_BUSY而無法呼叫 DxgkDdiBuildPagingBuffer

    如果驅動程式傳回STATUS_GRAPHICS_ALLOCATION_BUSY,視訊記憶體管理員會等到 GPU 以目前配置的任何參考完成,然後再次呼叫驅動程式的 DxgkDdiBuildPagingBuffer 函 式。 第二次呼叫 DxgkDdiBuildPagingBuffer 時,視訊記憶體管理員會在 DXGKARG_BUILDPAGINGBUFFER 之 Transfer 成員的 Flags 成員中設定 AllocationIsIdle 位字段旗標,以指出所參考的配置閑置。 如果未設定閑置旗標,驅動程序應該一律判斷配置目前忙碌中,或可能很快就會忙碌。 如果設定閑置旗標,視訊記憶體管理員會保證所參考的配置在呼叫 DxgkDdiBuildPagingBuffer 期間維持閑置狀態。

    如果DXGKARG_BUILDPAGINGBUFFER的 hAllocation 成員是 NULL,驅動程式應該將來源中的數據複製到目的地,而不需執行任何波浪或磚。

  • 填滿

    填滿作業會以指定的模式填滿配置。 填滿作業是用來設定配置的初始內容。 填滿配置的內容時,配置保證會閑置 (也就是 GPU) 不使用。 填滿作業只能在記憶體區段上執行。 視訊記憶體管理員永遠不會要求顯示器迷你埠驅動程序填滿光圈區段。

  • 捨棄內容

    discard-content 作業會通知驅動程式從記憶體區段中的配置目前位置捨棄配置。 也就是說,配置會收回,而不會複製到系統記憶體。

    在某些情況下,當特定配置分頁或記憶體不足時,可能需要驅動程式來設定硬體資源。 根據預設,GPU 可能會使用呼叫 DxgkDdiBuildPagingBuffer 期間所參考的配置。 在這些情況下,驅動程式可能需要配置閑置,驅動程式才能 (程式設計所需的硬體資源,也就是程式設計硬體資源無法在提供的 DMA 緩衝區) 中排入佇列。 在這種情況下,驅動程式可能會因為STATUS_GRAPHICS_ALLOCATION_BUSY而無法呼叫 DxgkDdiBuildPagingBuffer

    如果驅動程式傳回STATUS_GRAPHICS_ALLOCATION_BUSY,視訊記憶體管理員會等到 GPU 以目前配置的任何參考完成,然後再次呼叫驅動程式的 DxgkDdiBuildPagingBuffer 函 式。 第二次呼叫 DxgkDdiBuildPagingBuffer 時,視訊記憶體管理員會在 DXGKARG_BUILDPAGINGBUFFER 結構的 Flags 成員的 Flags 成員中設定 AllocationIsIdle 位字段旗標,以指出所參考的配置處於閑置狀態。 如果未設定閑置旗標,驅動程序應該一律判斷配置目前忙碌中,或可能很快就會忙碌。 如果設定閑置旗標,視訊記憶體管理員會保證所參考的配置在呼叫 DxgkDdiBuildPagingBuffer 期間維持閑置狀態。

  • 讀取實體

    讀取實體作業會從指定的物理記憶體位址讀取。 系統會要求驅動程式為作業編寫 GPU 的程式。 讀取所要存取的實體記憶體大小可以從1位元組到8個字節。 由於讀取的數據無關, 因此不需要 DxgkDdiBuildPagingBuffer 才能傳回數據。 不過,在 CPU 在 GPU 寫入該 AGP 記憶體之後嘗試從 AGP 記憶體讀取的案例中,讀取實體作業非常重要,以確保記憶體的一致性。

  • 寫入實體

    寫入實體作業會寫入指定的實體位址。 系統會要求驅動程式為作業編寫 GPU 的程式。 寫入作業所要存取的實體記憶體大小可以從1位元組到8個字節。 由於寫入的數據無關, 因此 DxgkDdiBuildPagingBuffer 可以將任何數據寫入記憶體。 不過,在 CPU 嘗試在 GPU 寫入該 AGP 記憶體之後從 AGP 記憶體讀取的案例中,寫入實體作業非常重要,以確保記憶體的一致性。

  • 地圖光圈區段

    map-aperture-segment 作業會將指定的記憶體描述元清單 (MDL) 對應至指定分頁數之指定區段位移的指定光圈區段。 如果在DXGKARG_BUILDPAGINGBUFFER結構的 MapApertureSegment 成員的 Flags 成員中設定 CacheCoherent 位字段旗標,則驅動程式必須確定已在對應的頁面上強制執行快取一致性;否則,對應之頁面不需要快取一致性。

    注意CacheCoherent 位欄位旗標只有在可快取記憶體對應到快取一致光圈區段,而且永遠不會在非快取一致光圈區段或對應至快取一致區段的寫入合併配置上設定。
     
    驅動程式可以選擇性地使用記憶體對應 I/O (MMIO) 來設定光圈區段。 GPU 不會在設定時間存取光圈範圍。 不過,此光圈設定不得干擾 GPU 的執行。 當已設定DXGK_OPERATION_MAP_APERTURE_SEGMENT作業類型來呼叫 DxgkDdiBuildPagingBuffer 時,GPU 將不會閑置,而且 GPU 可能會忙碌存取正在重新設定的光圈區段的其他部分。
  • 取消對應光圈區段

    unmap-aperture-segment 作業會取消對應先前所指定光圈區段的對應範圍。 驅動程式必須將未對應的範圍對應至DXGKARG_BUILDPAGINGBUFFER結構之 UnmapApertureSegment 成員之 DummyPage 成員的虛擬頁面。

    注意 當驅動程式取消對應至虛擬頁面時,驅動程式必須透過指定的光圈範圍啟用 GPU 存取,讓 DirectX 圖形核心子系統可以偵測損毀問題。 一致性測試存在以檢查這種情況。
     
    視訊記憶體管理員會使用光圈未對應的部分的虛擬頁面,來判斷記憶體管理員存取光圈區段的困難。

    驅動程式可以選擇性地使用MMIO來設定光圈區段。 GPU 不會在設定時間存取光圈範圍。 不過,此光圈設定不得干擾 GPU 的執行。 當已設定DXGK_OPERATION_UNMAP_APERTURE_SEGMENT作業類型來呼叫 DxgkDdiBuildPagingBuffer 時,GPU 將不會閑置,而且 GPU 可能會忙碌存取正在重新設定的光圈區段的其他部分。

  • 特殊鎖定傳輸

    特殊鎖定傳輸作業類似於一般傳輸作業。 不過,除了將配置的內容從 或傳輸至配置的一般備份存儲區,特殊鎖定傳輸作業會將配置的內容從 或 傳輸至使用UseAlternateVA位字段旗標來呼叫為配置所設定的替代虛擬位址。

    特殊鎖定傳輸作業只會發生在下列其中一個案例中:

    • 配置目前可透過替代虛擬位址存取CPU,並正在收回。
    • 先前收回的配置,例如上一個項目符號中所述的情況,會分頁回頁。
    不支援使用 UseAlternateVA 位欄位字段旗標的驅動程式將不會呼叫以執行特殊鎖定傳輸作業。

    在某些情況下,當特定配置分頁或記憶體不足時,可能需要驅動程式來設定硬體資源。 根據預設,GPU 可能會使用呼叫 DxgkDdiBuildPagingBuffer 期間所參考的配置。 在這些情況下,驅動程式可能需要配置閑置,驅動程式才能 (程式設計所需的硬體資源,也就是程式設計硬體資源無法在提供的 DMA 緩衝區) 中排入佇列。 在這種情況下,驅動程式可能會因為STATUS_GRAPHICS_ALLOCATION_BUSY而無法呼叫 DxgkDdiBuildPagingBuffer

    如果驅動程式傳回STATUS_GRAPHICS_ALLOCATION_BUSY,視訊記憶體管理員會等到 GPU 以目前配置的任何參考完成,然後再次呼叫驅動程式的 DxgkDdiBuildPagingBuffer 函 式。 第二次呼叫 DxgkDdiBuildPagingBuffer 時,視訊記憶體管理員會在DXGKARG_BUILDPAGINGBUFFER結構的 Flags 成員 Flags 成員中設定 AllocationIsIdle 位字段旗標,以指出所參考的配置處於閑置狀態。 如果未設定閑置旗標,驅動程序應該一律判斷配置目前忙碌中,或可能很快就會忙碌。 如果設定閑置旗標,視訊記憶體管理員會保證所參考的配置在呼叫 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