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 DxgkDdiBuildPagingBuffersuccessfully 페이징 버퍼를 빌드했습니다.
STATUS_GRAPHICS_ALLOCATION_BUSY GPU는 현재 페이징 버퍼에 대한 할당을 사용하고 있습니다.
STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER 페이징 버퍼(즉, pBuildPagingBuffer 매개 변수가 가리키는 DXGKARG_BUILDPAGINGBUFFER 구조체의 pDmaBuffer 멤버)에 더 많은 공간이 필요합니다.

설명

DxgkDdiBuildPagingBuffer 함수는 페이징 버퍼라고 하는 특수한 DMA(직접 메모리 액세스) 버퍼를 빌드하기 위해 호출됩니다. 페이징 버퍼에는 할당 부분의 콘텐츠를 이동하는 작업이 포함됩니다.

  • 할당의 세그먼트 내에서.
  • 할당 세그먼트 사이입니다.
  • 할당 세그먼트에서 시스템 메모리로.
  • 시스템 메모리에서 할당 세그먼트로.

디스플레이 미니포트 드라이버는 요청된 페이징 작업에 따라 제공된 페이징 버퍼(DXGKARG_BUILDPAGINGBUFFERpDmaBuffer 멤버)에 적절한 GPU(그래픽 처리 장치) 명령을 작성해야 합니다. 그러면 드라이버가 페이징 버퍼를 비디오 메모리 관리자(Dxgkrnl.sys)로 다시 반환해야 합니다. GPU 스케줄러(Dxgkrnl.sys일부이기도 함)는 이후에 드라이버의 DxgkDdiSubmitCommand 함수를 호출하여 드라이버가 페이징 버퍼를 GPU에 일반 DMA 버퍼로 제출하도록 요청합니다.

참고 비디오 메모리 관리자가 페이징 버퍼를 제출하기 전에 드라이버의 DxgkDdiPatch 함수를 호출하여 페이징 버퍼에 물리적 주소(즉, 패치)를 할당합니다. 그러나 DxgkDdiPatch 호출 시 비디오 메모리 관리자는 패치 위치 목록을 제공하지 않습니다. 드라이버의 DxgkDdiPatch 함수는 페이징 버퍼에 대한 막판 업데이트를 수행할 수 있습니다. 그러나 드라이버의 DxgkDdiPatch 함수는 페이징 버퍼의 크기를 변경할 수 없습니다.
 
드라이버가 페이징 버퍼를 성공적으로 빌드하면 드라이버의 DxgkDdiBuildPagingBufferpDmaBuffer 를 업데이트하여 페이징 버퍼에 기록된 마지막 바이트를 가리킨 다음 STATUS_SUCCESS 반환해야 합니다. DxgkDdiBuildPagingBuffer는 페이징 버퍼의 공간이 부족한 경우에만 실패할 수 있으므로 드라이버는 항상 페이징 버퍼가 버퍼에 쓰기 전에 충분한 공간이 남아 있는지 확인해야 합니다. 페이징 버퍼에 공간이 충분하지 않은 경우 드라이버는 STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER 반환해야 합니다. 그런 다음 비디오 메모리 관리자는 새 페이징 버퍼를 획득하고 드라이버의 DxgkDdiBuildPagingBuffer 함수를 다시 호출하여 요청된 페이징 작업에 따라 새 페이징 버퍼를 채웁니다. 여러 페이징 버퍼를 채우는 지정된 요청된 페이징 작업의 경우 스케줄러는 각 부분 페이징 버퍼에 대해 드라이버의 DxgkDdiSubmitCommand 함수를 여러 번 호출하여 각 버퍼를 독립적으로 제출합니다.

DxgkDdiBuildPagingBuffer가 페이징 작업에 둘 이상의 페이징 버퍼가 필요하다고 판단하는 경우 드라이버는 DXGKARG_BUILDPAGINGBUFFERMultipassOffset 멤버에 정보를 지정할 수 있으며 페이징 작업의 여러 반복에서 이 정보를 사용할 수 있습니다. 비디오 메모리 관리자는 첫 번째 페이징 작업 요청 전에 MultipassOffset 의 정보를 0으로 초기화하고 반복 간에 MultipassOffset 의 정보를 수정하지 않습니다. 따라서 드라이버는 MultipassOffset 을 사용하여 반복 간의 진행률을 저장할 수 있습니다. 예를 들어 드라이버는 페이징 기반 전송을 위해 마지막으로 전송된 페이지 번호를 저장할 수 있습니다.

페이징 버퍼는 현재 다음과 같은 유형의 작업에 대해 빌드됩니다.

  • 전송

    전송 작업은 할당 콘텐츠를 한 위치에서 다른 위치로 이동합니다. 이 작업은 가장 일반적인 유형의 메모리 작업입니다.

    할당은 항상 한 위치에서 다른 위치로 완전히 전송됩니다. 그러나 메모리 제약 조건으로 인해 할당 전송은 여러 하위 전송으로 나눌 수 있습니다(즉, 할당의 일부가 위치 A에서 B로 이동된 다음 전체 할당이 전송될 때까지 다음 부분이 이동됨). 할당의 첫 번째 하위 전송은 DXGKARG_BUILDPAGINGBUFFER Transfer 멤버의 Flags 멤버에 TransferStart 비트 필드 플래그로 표시됩니다. 할당의 마지막 하위 전송은 TransferEnd 비트 필드 플래그로 표시됩니다. 드라이버는 드라이버가 새 전송의 시작을 받기 전에 보류 중인 전송(즉, 마지막 하위 전송)의 끝을 수신하도록 보장됩니다.

    각 하위 전송을 완료하려면 DxgkDdiBuildPagingBuffer 에 대한 여러 호출이 필요할 수 있습니다(예: 드라이버가 DMA 버퍼 공간이 부족할 수 있습니다). 따라서 드라이버가 DxgkDdiBuildPagingBuffer 호출에서 TransferEnd 플래그를 받을 때까지 DxgkDdiBuildPagingBuffer에 대한 여러 호출에서 TransferStart 플래그를 받을 수 있습니다. 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에서 사용하지 않음). 채우기 작업은 메모리 세그먼트에서만 수행할 수 있습니다. 비디오 메모리 관리자는 디스플레이 미니포트 드라이버가 조리개 세그먼트를 채우라고 요청하지 않습니다.

  • 콘텐츠 삭제

    삭제 콘텐츠 작업은 메모리 세그먼트에 있는 할당의 현재 위치에서 할당이 삭제되었음을 드라이버에 알립니다. 즉, 할당이 제거되고 시스템 메모리에 다시 복사되지 않습니다.

    일부 시나리오에서는 특정 할당이 메모리 내 또는 외부로 페이징될 때 드라이버가 하드웨어 리소스를 설정해야 할 수 있습니다. 기본적으로 GPU는 DxgkDdiBuildPagingBuffer를 호출하는 동안 참조되는 할당을 사용할 수 있습니다. 이러한 시나리오에서 드라이버는 드라이버가 필요한 하드웨어 리소스를 프로그래밍하기 전에 할당을 유휴 상태로 설정해야 할 수 있습니다(즉, 제공된 DMA 버퍼에서 하드웨어 리소스를 큐에 대기할 수 없음). 이러한 시나리오의 경우 드라이버는 STATUS_GRAPHICS_ALLOCATION_BUSY 사용하여 DxgkDdiBuildPagingBuffer 호출에 실패할 수 있습니다.

    드라이버가 STATUS_GRAPHICS_ALLOCATION_BUSY 반환하면 비디오 메모리 관리자는 GPU가 현재 할당에 대한 참조로 완료될 때까지 기다린 다음 드라이버의 DxgkDdiBuildPagingBuffer 함수를 다시 호출합니다. DxgkDdiBuildPagingBuffer에 대한 두 번째 호출에서 비디오 메모리 관리자는 참조되는 할당이 유휴 상태임을 나타내기 위해 DXGKARG_BUILDPAGINGBUFFER 구조체의 DiscardContent 멤버의 Flags 멤버에 AllocationIsIdle 비트 필드 플래그를 설정합니다. 유휴 플래그가 설정되지 않은 경우 드라이버는 항상 할당이 현재 사용 중이거나 곧 사용 중일 수 있음을 확인해야 합니다. 유휴 플래그가 설정되면 비디오 메모리 관리자는 참조되는 할당이 DxgkDdiBuildPagingBuffer 호출 기간 동안 유휴 상태로 유지되도록 보장합니다.

  • 실제 읽기

    읽기-물리적 작업은 지정된 실제 메모리 주소에서 읽습니다. 드라이버가 작업에 대한 GPU를 프로그래밍하도록 요청됩니다. 읽기에 액세스할 실제 메모리의 크기는 1바이트에서 8바이트까지입니다. 읽은 데이터는 관련이 없으므로 DxgkDdiBuildPagingBuffer 는 데이터를 반환할 필요가 없습니다. 그러나 GPU가 해당 AGP 메모리에 쓴 후 CPU가 AGP 메모리에서 읽으려고 시도하는 시나리오에서는 메모리 일관성을 보장하기 위해 읽기-물리적 작업이 중요합니다.

  • 물리적 쓰기

    쓰기-물리적 작업은 지정된 실제 주소에 씁니다. 드라이버가 작업에 대한 GPU를 프로그래밍하도록 요청됩니다. 쓰기 작업에 액세스할 실제 메모리의 크기는 1바이트에서 8바이트까지입니다. 작성된 데이터는 관련이 없으므로 DxgkDdiBuildPagingBuffer 는 메모리에 데이터를 쓸 수 있습니다. 그러나 GPU가 해당 AGP 메모리에 쓴 후 CPU가 AGP 메모리에서 읽으려고 시도하는 시나리오에서는 메모리 일관성을 보장하기 위해 쓰기 물리적 작업이 중요합니다.

  • 지도 조리개 세그먼트

    map-aperture-segment 작업은 지정된 수의 페이지에 대해 지정된 세그먼트 오프셋에서 지정된 MDL(메모리 설명자 목록)을 지정된 조리개 세그먼트에 매핑합니다. cacheCoherent 비트 필드 플래그가 DXGKARG_BUILDPAGINGBUFFER 구조체의 MapApertureSegment 멤버의 Flags 멤버에 설정된 경우 드라이버는 매핑된 페이지에 캐시 일관성이 적용되는지 확인해야 합니다. 그렇지 않으면 매핑된 페이지에 캐시 일관성이 필요하지 않습니다.

    참고CacheCoherent 비트 필드 플래그는 캐시 가능한 메모리가 캐시 일관성 있는 조리개 세그먼트에 매핑되고 캐시 일관성이 없는 조리개 세그먼트 또는 캐시 일관성 세그먼트에 매핑되는 쓰기 결합 할당에서 설정되지 않는 경우에만 설정됩니다.
     
    드라이버는 필요에 따라 MMIO(메모리 매핑 I/O)를 사용하여 조리개 세그먼트를 구성할 수 있습니다. GPU는 구성 시 조리개 범위에 액세스하지 않습니다. 그러나 이 조리개 구성은 GPU 실행을 방해해서는 안됩니다. DXGK_OPERATION_MAP_APERTURE_SEGMENT 작업 유형이 설정된 DxgkDdiBuildPagingBuffer 가 호출되고 GPU가 다시 구성되는 조리개 세그먼트의 다른 부분에 액세스하는 데 사용 중일 수 있는 경우 GPU는 유휴 상태가 되지 않습니다.
  • 조리개 세그먼트 매핑 해제

    unmap-aperture-segment 작업은 이전에 매핑된 지정된 조리개 세그먼트 범위의 매핑을 해제합니다. 드라이버는 DXGKARG_BUILDPAGINGBUFFER 구조체UnmapApertureSegment 멤버의 DummyPage 멤버가 지정하는 더미 페이지에 매핑되지 않은 범위를 매핑해야 합니다.

    참고 드라이버가 더미 페이지에 매핑을 해제하면 드라이버는 DirectX 그래픽 커널 하위 시스템이 손상 문제를 감지할 수 있도록 지정된 조리개 범위를 통해 GPU 액세스를 사용하도록 설정해야 합니다. 이 상황을 검사 준수 테스트가 있습니다.
     
    비디오 메모리 관리자는 조리개에서 매핑되지 않은 부분에 있는 더미 페이지를 사용하여 메모리 관리자가 조리개 세그먼트에 액세스하는 데 발생하는 어려움을 확인합니다.

    드라이버는 필요에 따라 MMIO를 사용하여 조리개 세그먼트를 구성할 수 있습니다. GPU는 구성 시 조리개 범위에 액세스하지 않습니다. 그러나 이 조리개 구성은 GPU 실행을 방해해서는 안됩니다. DxgkDdiBuildPagingBuffer가 DXGK_OPERATION_UNMAP_APERTURE_SEGMENT 작업 유형 집합으로 호출되고 GPU가 다시 구성되는 조리개 세그먼트의 다른 부분에 액세스하는 데 사용 중일 수 있는 경우 GPU는 유휴 상태가 되지 않습니다.

  • 특수 잠금 전송

    특수 잠금 전송 작업은 일반 전송 작업과 유사합니다. 그러나 할당의 콘텐츠를 할당의 일반 백업 저장소에서 또는 로 전송하는 대신, 특수 잠금 전송 작업은 pfnLockCb 함수가 UseAlternateVA 비트 필드 플래그 집합으로 호출될 때 할당에 대해 설정된 대체 가상 주소에서 또는 에서 할당 콘텐츠를 전송합니다.

    특수 잠금 전송 작업은 다음 시나리오 중 하나에서만 발생합니다.

    • 할당은 현재 대체 가상 주소로 CPU에 액세스할 수 있으며 제거되고 있습니다.
    • 이전 글머리 기호에 설명된 상황과 같이 이전에 제거된 할당이 다시 페이징되고 있습니다.
    UseAlternateVA 비트 필드 플래그 사용을 지원하지 않는 드라이버는 특수 잠금 전송 작업을 수행하기 위해 호출되지 않습니다.

    일부 시나리오에서는 특정 할당이 메모리 내 또는 외부로 페이징될 때 드라이버가 하드웨어 리소스를 설정해야 할 수 있습니다. 기본적으로 GPU는 DxgkDdiBuildPagingBuffer를 호출하는 동안 참조되는 할당을 사용할 수 있습니다. 이러한 시나리오에서 드라이버는 드라이버가 필요한 하드웨어 리소스를 프로그래밍하기 전에 할당을 유휴 상태로 설정해야 할 수 있습니다(즉, 제공된 DMA 버퍼에서 하드웨어 리소스를 큐에 대기할 수 없음). 이러한 시나리오의 경우 드라이버는 STATUS_GRAPHICS_ALLOCATION_BUSY 사용하여 DxgkDdiBuildPagingBuffer 호출에 실패할 수 있습니다.

    드라이버가 STATUS_GRAPHICS_ALLOCATION_BUSY 반환하면 비디오 메모리 관리자는 GPU가 현재 할당에 대한 참조로 완료될 때까지 기다린 다음 드라이버의 DxgkDdiBuildPagingBuffer 함수를 다시 호출합니다. DxgkDdiBuildPagingBuffer에 대한 두 번째 호출에서 비디오 메모리 관리자는 참조되는 할당이 유휴 상태임을 나타내기 위해 DXGKARG_BUILDPAGINGBUFFER 구조체의 SpecialLockTransfer 멤버의 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