다음을 통해 공유


사용자 모드 작업 제출

Important

일부 정보는 상용 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

이 문서에서는 Windows 11 버전 24H2(WDDM 3.2)를 기준으로 아직 개발 중인 UM(사용자 모드) 작업 제출 기능에 대해 설명합니다. UM 작업 제출을 사용하면 애플리케이션이 대기 시간이 매우 짧은 사용자 모드에서 직접 GPU에 작업을 제출할 수 있습니다. 목표는 GPU에 작은 워크로드를 자주 제출하는 애플리케이션의 성능을 향상시키는 것입니다. 또한 사용자 모드 제출은 컨테이너 또는 VM(가상 머신) 내에서 실행되는 경우 이러한 애플리케이션에 상당한 도움이 될 것으로 예상됩니다. 이 장점은 VM에서 실행되는 UMD(사용자 모드 드라이버)가 호스트에 메시지를 보내지 않고도 GPU에 작업을 직접 제출할 수 있기 때문입니다.

UM 작업 제출을 지원하는 IHV 드라이버 및 하드웨어는 기존의 커널 모드 작업 제출 모델을 동시에 계속 지원해야 합니다. 이 지원은 최신 호스트에서 실행되는 기존 KM 큐만 지원하는 이전 게스트와 같은 시나리오에 필요합니다.

이 문서에서는 Flip/FlipEx와의 UM 제출 상호 운용성에 대해 설명하지 않습니다. 이 문서에서 설명하는 UM 제출은 시나리오의 렌더링 전용/컴퓨팅 클래스로 제한됩니다. 프레젠테이션 파이프라인은 네이티브 모니터링 펜스에 종속되어 있으므로 현재 커널 모드 제출을 기반으로 합니다. UM 제출 기반 프레젠테이션의 디자인 및 구현은 네이티브 모니터링 펜스 및 컴퓨팅/렌더링에 대한 UM 제출이 완전히 구현된 후에 고려할 수 있습니다. 따라서 드라이버는 큐별로 사용자 모드 제출을 지원해야 합니다.

초인종

하드웨어 예약을 지원하는 대부분의 최신 또는 향후 세대의 GPU는 GPU 초인종의 개념도 지원합니다. 초인종은 GPU 엔진에 새 작업이 작업 큐에 대기 중임을 나타내는 메커니즘입니다. 초인종은 일반적으로 PCIe BAR(기본 주소 표시줄) 또는 시스템 메모리에 등록됩니다. 각 GPU IHV에는 초인종의 수, 시스템에 있는 위치 등을 결정하는 자체 아키텍처가 있습니다. Windows OS는 디자인의 일부로 초인종을 사용하여 UM 작업 제출을 구현합니다.

높은 수준에서 다른 IHV 및 GPU에서 구현하는 두 가지 초인종 모델이 있습니다.

  • 전역 초인종

    Global Doorbells 모델에서 컨텍스트 및 프로세스의 모든 하드웨어 큐는 단일 전역 초인종을 공유합니다. 초인종에 기록된 값은 GPU 스케줄러에 새로운 작업이 있는 특정 하드웨어 큐 및 엔진에 대해 알려줍니다. GPU 하드웨어는 여러 하드웨어 큐가 작업을 적극적으로 제출하고 동일한 전역 초인종을 울리는 경우 폴링 메커니즘의 형태를 사용하여 작업을 가져옵니다.

  • 전용 초인종

    전용 초인종 모델에서 각 하드웨어 큐에는 GPU에 제출할 새 작업이 있을 때마다 실행되는 고유한 초인종이 할당됩니다. 초인종이 실행되면 GPU 스케줄러는 새 작업을 제출한 하드웨어 큐를 정확히 알고 있습니다. GPU에서 만든 모든 하드웨어 큐에서 공유되는 제한된 초인종이 있습니다. 만든 하드웨어 큐 수가 사용 가능한 초인종 수를 초과하는 경우 드라이버는 이전 또는 최근에 사용한 하드웨어 큐의 초인종 연결을 끊고 초인종을 새로 만든 큐에 할당하여 초인종을 효과적으로 "가상화"해야 합니다.

사용자 모드 작업 제출 지원 검색

DXGK_NODEMETADATA_FLAGS::UserModeSubmissionSupported

UM 작업 제출 기능을 지원하는 GPU 노드의 경우 KMD의 DxgkDdiGetNodeMetadata는 DXGK_NODEMETADATA_FLAGS 추가되는 UserModeSubmissionSupported 노드 메타데이터 플래그를 설정합니다. 그런 다음 OS를 통해 UMD는 이 플래그가 설정된 노드에서만 사용자 모드 제출 HWQueues 및 초인종을 만들 수 있습니다.

DXGK_QUERYADAPTERINFOTYPE::D XGKQAITYPE_USERMODESUBMISSION_CAPS

초인종 관련 정보를 쿼리하기 위해 OS는 DXGKQAITYPE_USERMODESUBMISSION_CAPS 쿼리 어댑터 정보 유형을 사용하여 KMD의 DxgkDdiQueryAdapterInfo 함수를 호출합니다. KMD는 사용자 모드 작업 제출에 대한 지원 세부 정보로 DXGK_USERMODESUBMISSION_CAPS 구조를 채워 응답합니다.

현재 필요한 유일한 캡은 초인종 메모리 크기(바이트)입니다. Dxgkrnl 에는 다음과 같은 몇 가지 이유로 초인종 메모리 크기가 필요합니다.

  • 초인종을 만드는 동안(D3DKMTCreateDoorbell) Dxgkrnl은 DoorbellCpuVirtualAddress를 UMD로 반환합니다. 이렇게 하기 전에 초인종이 아직 할당되고 연결되지 않았기 때문에 Dxgkrnl 은 먼저 내부적으로 더미 페이지에 매핑해야 합니다. 더미 페이지를 할당하려면 초인종의 크기가 필요합니다.
  • 초인종 연결(D3DKMT커넥트Doorbell) 중에 Dxgkrnl은 DOORbellCpuVirtualAddress를 KMD에서 제공하는 DoorbellPhysicalAddress로 회전해야 합니다. 다시 말하지만, Dxgkrnl 은 초인종 크기를 알아야 합니다.

D3DDDI_CREATEHWQUEUEFLAGS::UserModeSubmission in D3DKMTCreateHwQueue

UMD는 사용자 모드 제출 모델을 사용하는 HWQueues를 만들기 위해 D3DDDI_CREATEHWQUEUEFLAGS 추가된 UserModeSubmission 플래그를 설정합니다. 이 플래그를 사용하여 만든 HWQueues는 일반 커널 모드 작업 제출 경로를 사용할 수 없으며 큐에서 작업 제출을 위해 초인종 메커니즘을 사용해야 합니다.

사용자 모드 작업 제출 API

사용자 모드 작업 제출을 지원하기 위해 다음 사용자 모드 API가 추가됩니다.

  • D3DKMTCreateDoorbell 은 사용자 모드 작업 제출을 위해 D3D HWQueue에 대한 초인종을 만듭니다.

  • D3DKMT커넥트Doorbell은 사용자 모드 작업 제출을 위해 이전에 만든 초인종을 D3D HWQueue에 연결합니다.

  • D3DKMTDestroyDoorbell 은 이전에 만든 초인종을 파괴합니다.

  • D3DKMTNotifyWorkSubmission 은 KMD에 HWQueue에 새 작업이 제출되었음을 알렸습니다. 이 기능의 요점은 짧은 대기 시간 작업 제출 경로입니다. 여기서 KMD는 작업이 제출될 때 관련되거나 인식되지 않습니다. 이 API는 HWQueue에서 작업이 제출될 때마다 KMD에 알림을 받아야 하는 시나리오에서 유용합니다. 드라이버는 모든 작업 제출 시 UMD에서 KMD로의 왕복을 포함하므로 대기 시간이 짧은 사용자 모드 제출 모델의 목적을 무용지물로 만들기 때문에 이 메커니즘을 특정하고 드문 시나리오에서 사용해야 합니다.

초인종 메모리 및 링 버퍼 할당의 상주 모델

  • UMD는 초인종을 만들기 전에 링 버퍼 및 링 버퍼 컨트롤 할당을 상주하는 역할을 합니다.
  • UMD는 링 버퍼 및 링 버퍼 컨트롤 할당의 수명을 관리합니다. Dxgkrnl 은 해당 초인종이 제거되더라도 이러한 할당을 암시적으로 삭제하지 않습니다. UMD는 이러한 할당을 할당하고 삭제하는 역할을 담당합니다. 그러나 초인종이 활성 상태인 동안 악의적인 사용자 모드 프로그램이 이러한 할당을 파괴하지 않도록 하기 위해 Dxgkrnl 은 초인종의 수명 동안 참조를 수행합니다.
  • Dxgkrnl링 버퍼 할당을 삭제하는 유일한 시나리오는 디바이스 종료 중입니다. Dxgkrnl 은 디바이스와 연결된 모든 HWQueues, 초인종 및 링 버퍼 할당을 제거합니다.
  • 링 버퍼 할당이 활성 상태인 한 링 버퍼 CPUVA는 항상 유효하며 초인종 연결 상태 관계없이 UMD에서 액세스할 수 있습니다. 즉, 링 버퍼 레지던시는 초인종에 연결되지 않습니다.
  • KMD가 초인종 연결을 끊기 위해 DXG 콜백을 만들면(즉, 상태 D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY DxgkCbDisconnectDoorbell을 호출함) Dxgkrnl은 초인종 CPUVA를 더미 페이지로 회전합니다. 링 버퍼 할당을 제거하거나 매핑 해제하지 않습니다.
  • 디바이스 손실 시나리오(TDR/GPU 중지/페이지 등)의 경우 Dxgkrnl은 초인종의 연결을 끊고 상태 D3DDDI_DOORBELL_STATUS_DISCONNECTED_ABORT 표시합니다. 사용자 모드는 HWQueue, 초인종, 링 버퍼를 삭제하고 다시 만드는 역할을 합니다. 이 요구 사항은 이 시나리오에서 다른 디바이스 리소스를 제거하고 다시 만드는 방법과 유사합니다.

하드웨어 컨텍스트 일시 중단

OS가 하드웨어 컨텍스트 를 일시 중단하면 Dxgkrnl 은 초인종 연결을 활성으로 유지하고 링 버퍼(작업 큐) 할당을 상주합니다. 이러한 방식으로 UMD는 컨텍스트에 대한 큐 작업을 계속할 수 있습니다. 컨텍스트가 일시 중단되는 동안에는 이 작업이 예약되지 않습니다. 컨텍스트가 다시 시작되고 예약되면 GPU의 CMP(컨텍스트 관리 프로세서)는 새 쓰기 포인터 및 작업 제출을 관찰합니다.

이 논리는 UMD가 일시 중단된 컨텍스트를 사용하여 D3DKMTSubmitCommand를 호출할 수 있는 현재 커널 모드 제출 논리와 유사합니다. Dxgkrnl 은 이 새 명령을 HwQueue에 큐에 추가하지만 나중에 예약될 때까지 예약되지 않습니다.

다음 이벤트 시퀀스는 하드웨어 컨텍스트 일시 중단 및 다시 시작 중에 발생합니다.

  • 하드웨어 컨텍스트 일시 중단:

    1. Dxgkrnl 은 DxgkddiSuspendContext를 호출 합니다.
    2. KMD는 HW 스케줄러 목록에서 컨텍스트의 모든 HWQueue를 제거합니다.
    3. 초인종은 여전히 연결되어 있으며 링 버퍼/링 버퍼 컨트롤 할당은 여전히 상주합니다. UMD는 이 컨텍스트의 HWQueue에 새 명령을 쓸 수 있지만 GPU는 이를 처리하지 않습니다. 이는 일시 중단된 컨텍스트에 대한 오늘날의 커널 모드 명령 제출과 유사합니다.
    4. KMD가 일시 중단된 HWQueue의 초인종을 희생하도록 선택하면 UMD의 연결이 끊어집니다. UMD는 초인종을 다시 연결하려고 시도할 수 있으며 KMD는 이 큐에 새 초인종을 할당합니다. UMD를 중단하는 것이 아니라 컨텍스트가 다시 시작된 후 HW 엔진이 결국 처리할 수 있는 작업을 계속 제출하도록 허용하는 것입니다.
  • 하드웨어 컨텍스트 다시 시작:

    1. Dxgkrnl 은 DxgkddiResumeContext를 호출 합니다.
    2. KMD는 컨텍스트의 모든 HWQueue를 HW 스케줄러 목록에 추가합니다.

엔진 F-상태 전환

기존의 커널 모드 작업 제출 에서 Dxgkrnl 은 HWQueue에 새 명령을 제출하고 KMD의 완료 인터럽트 모니터링을 담당합니다. 이러한 이유로 Dxgkrnl 은 엔진이 활성 상태이고 유휴 상태인 경우를 완전히 볼 수 있습니다.

사용자 모드 작업 제출 에서 Dxgkrnl 은 GPU 엔진이 TDR 시간 제한 주기를 사용하여 진행 중인지 여부를 모니터링하므로 2초 TDR 시간 제한보다 빨리 F1 상태로 전환을 시작하는 것이 가치있는 경우 KMD는 OS에 이를 요청할 수 있습니다.

이 방법을 용이하게 하기 위해 다음과 같은 변경이 수행되었습니다.

  • DXGK_INTERRUPT_GPU_ENGINE_STATE_CHANGE 인터럽트 형식이 DXGK_INTERRUPT_TYPE 추가됩니다. KMD는 이 인터럽트를 사용하여 GPU 전원 작업 또는 Active - TransitionToF1 및 Active ->> Hung같은 시간 제한 복구가 필요한 엔진 상태 전환을 Dxgkrnl에 알립니다.

  • EngineStateChange 인터럽트 데이터 구조가 DXGKARGCB_NOTIFY_INTERRUPT_DATA 추가됩니다.

  • DXGK_ENGINE_STATE 열거형은 EngineStateChange의 엔진 상태 전환을 나타내기 위해 추가됩니다.

KMD에서 EngineStateChange.NewState가 DXGK_ENGINE_STATE_TRANSITION_TO_F1 설정된 DXGK_INTERRUPT_GPU_ENGINE_STATE_CHANGE 인터럽트를 발생하면 Dxgkrnl은 이 엔진에서 HWQueues의 모든 초인종 연결을 끊은 다음 F0에서 F1로 전원 구성 요소 전환을 시작합니다.

UMD가 F1 상태의 GPU 엔진에 새 작업을 제출하려고 하면 초인종을 다시 연결해야 하며, 이로 인해 Dxgkrnl 이 F0 전원 상태로 다시 전환을 시작합니다.

엔진 D 상태 전환

D0에서 D3 디바이스 전원 상태 전환 중에 Dxgkrnl은 HWQueue를 일시 중단하고, 초인종 CPUVA를 더미 페이지로 회전)하고, DoorbellStatusCpuVirtualAddress 초인종 상태 D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY 업데이트합니다.

GPU가 D3에 있을 때 UMD가 D3DKMT커넥트Doorbell을 호출하면 Dxgkrnl이 GPU를 D0으로 깨워야 합니다. Dxgkrnl 은 또한 HWQueue를 다시 시작하고 초인종 CPUVA를 실제 초인종 위치로 회전하는 작업을 담당합니다.

다음 이벤트 시퀀스가 발생합니다.

  • D0~D3 GPU 전원이 다운됩니다.

    1. Dxgkrnl은 GPU의 모든 HW 컨텍스트에 대해 DxgkddiSuspendContext를 호출합니다. KMD는 HW 스케줄러 목록에서 이러한 컨텍스트를 제거합니다.
    2. Dxgkrnl은 모든 초인종의 연결을 끊습니다.
    3. Dxgkrnl 은 필요한 경우 VRAM에서 모든 링 버퍼/링 버퍼 컨트롤 할당을 제거할 수 있습니다. 하드웨어에서 제거된 메모리를 참조하지 않도록 모든 컨텍스트가 일시 중단되고 하드웨어 스케줄러 목록에서 제거되면 이 작업을 수행합니다.
  • GPU가 D3 상태일 때 UMD는 HWQueue에 새 명령을 씁니다.

    1. UMD에서는 초인종 연결이 끊어지므로 D3DKMT커넥트Doorbell을 호출합니다.
    2. Dxgkrnl 은 D0 전환을 시작합니다.
    3. Dxgkrnl 은 제거된 경우 모든 링 버퍼/링 버퍼 컨트롤 할당을 상주합니다.
    4. Dxgkrnl 은 KMD의 DxgkddiCreateDoorbell 함수를 호출하여 KMD가 이 HWQueue에 대한 초인종 연결을 만들도록 요청합니다.
    5. Dxgkrnl은 모든 HWContext에 대해 DxgkddiResumeContext를 호출합니다. KMD는 HW 스케줄러 목록에 해당 큐를 추가합니다.

사용자 모드 작업 제출을 위한 DPI

KMD 구현 DDI

사용자 모드 작업 제출 지원을 구현하기 위해 KMD에 대해 다음 커널 모드 DD가 추가되었습니다.

Dxgkrnl 구현 DDI

DxgkCbDisconnectDoorbell 콜백은 Dxgkrnl에 의해 구현됩니다. KMD는 이 함수를 호출하여 KMD가 특정 초인종의 연결을 끊어야 한다고 Dxgkrnl에 알릴 수 있습니다.

HW 큐 진행률 펜스 변경

UM 작업 제출 모델에서 실행되는 하드웨어 큐에는 명령 버퍼가 완료될 때 UMD에서 생성하고 쓰는 단조로 증가하는 진행률 펜스 값의 개념이 여전히 있습니다. Dxgkrnl이 특정 하드웨어 큐에 보류 중인 작업이 있는지 여부를 확인하려면 UMD는 링 버퍼에 새 명령 버퍼를 추가하고 GPU에 표시하기 직전에 대기 중인 진행률 펜스 값을 업데이트해야 합니다. CreateDoorbell.HwQueueProgressFenceLastQueuedValueCPUVirtualAddress 는 대기 중인 최신 값의 읽기/쓰기 사용자 모드 프로세스 매핑입니다.

UMD는 새 제출이 GPU에 표시되기 직전에 큐에 대기 중인 값이 업데이트되도록 하는 것이 중요합니다. 다음 단계는 권장되는 작업 시퀀스입니다. HW 큐가 유휴 상태이고 마지막으로 완성된 버퍼에 진행률 펜스 값 이 N인 것으로 가정합니다.

  • 새 진행률 펜스 값 N+1을 생성합니다.
  • 명령 버퍼를 채웁니다. 명령 버퍼의 마지막 명령은 N+1쓰는 진행률 펜스 값입니다.
  • *(HwQueueProgressFenceLastQueuedValueCPUVirtualAddress)를 N+1로 설정하여 새로 큐에 대기 중인 값의 OS에 알릴 수 있습니다.
  • 명령 버퍼를 링 버퍼에 추가하여 GPU에 표시되도록 합니다.
  • 초인종을 울림합니다.

정상 및 비정상적인 프로세스 종료

다음 이벤트 시퀀스는 정상적인 프로세스 종료 중에 발생합니다.

디바이스/컨텍스트의 각 HWQueue에 대해 다음을 수행합니다.

  1. Dxgkrnl은 DxgkDdiDisconnectDoorbell을 호출하여 초인종 연결을 끊습니다.
  2. Dxgkrnl 은 마지막 대기 중인 HwQueueProgressFenceLastQueuedValueCPUVirtualAddress 가 GPU에서 완료될 때까지 기다립니다. 링 버퍼/링 버퍼 컨트롤 할당이 다시 기본.
  3. Dxgkrnl의 대기가 충족되고 이제 링 버퍼/링 버퍼 컨트롤 할당, 초인종 및 HWQueue 개체를 삭제할 수 있습니다.

다음 이벤트 시퀀스는 비정상적인 프로세스 종료 중에 발생합니다.

  1. Dxgkrnl 은 디바이스를 오류로 표시합니다.

  2. 각 디바이스 컨텍스트에 대해 Dxgkrnl은 DxgkddiSuspendContext를 호출하여 컨텍스트를 일시 중단합니다. 링 버퍼/링 버퍼 컨트롤 할당은 여전히 상주합니다. KMD는 컨텍스트를 선점하고 HW 실행 목록에서 제거합니다.

  3. 컨텍스트의 각 HWQueue에 대해 Dxglrnl:

    a. DxgkDdiDisconnectDoorbell을 호출하여 초인종 연결을 끊습니다.

    b. 링 버퍼/링 버퍼 컨트롤 할당 및 초인종 및 HWQueue 개체를 제거합니다.

의사 코드 예제

UMD의 작업 제출 의사 코드

다음 의사 코드는 UMD가 초인종 API를 사용하여 HWQueues에 작업을 만들고 제출하는 데 사용해야 하는 모델의 기본 예제입니다. 기존 D3DKMTCreateHwQueue API를 사용하여 플래그를 UserModeSubmission 사용하여 만든 HWQueue에 대한 핸들을 고려 hHWqueue1 합니다.

// Create a doorbell for the HWQueue
D3DKMT_CREATE_DOORBELL CreateDoorbell = {};
CreateDoorbell.hHwQueue = hHwQueue1;
CreateDoorbell.hRingBuffer = hRingBufferAlloc;
CreateDoorbell.hRingBufferControl = hRingBufferControlAlloc;
CreateDoorbell.Flags.Value = 0;

NTSTATUS ApiStatus =  D3DKMTCreateDoorbell(&CreateDoorbell);
if(!NT_SUCCESS(ApiStatus))
  goto cleanup;

assert(CreateDoorbell.DoorbellCPUVirtualAddress!=NULL && 
      CreateDoorbell.DoorbellStatusCPUVirtualAddress!=NULL);

// Get a CPUVA of Ring buffer control alloc to obtain write pointer.
// Assume the write pointer is at offset 0 in this alloc
D3DKMT_LOCK2 Lock = {};
Lock.hAllocation = hRingBufferControlAlloc;
ApiStatus = D3DKMTLock2(&Lock);
if(!NT_SUCCESS(ApiStatus))
  goto cleanup;

UINT64* WritePointerCPUVirtualAddress = (UINT64*)Lock.pData;

// Doorbell created successfully. Submit command to this HWQueue

UINT64 DoorbellStatus = 0;
do
{
  // first connect the doorbell and read status
  ApiStatus = D3DKMTConnectDoorbell(hHwQueue1);
  D3DDDI_DOORBELL_STATUS DoorbellStatus = *(UINT64*(CreateDoorbell.DoorbellStatusCPUVirtualAddress));

  if(!NT_SUCCESS(ApiStatus) ||  DoorbellStatus == D3DDDI_DOORBELL_STATUS_DISCONNECTED_ABORT)
  {
    // fatal error in connecting doorbell, destroy this HWQueue and re-create using traditional kernel mode submission.
    goto cleanup_fallback;
  }

  // update the last queue progress fence value
  *(CreateDoorbell.HwQueueProgressFenceLastQueuedValueCPUVirtualAddress) = new_command_buffer_progress_fence_value;

  // write command to ring buffer of this HWQueue
  *(WritePointerCPUVirtualAddress) = address_location_of_command_buffer;

  // Ring doorbell by writing the write pointer value into doorbell address. 
  *(CreateDoorbell.DoorbellCPUVirtualAddress) = *WritePointerCPUVirtualAddress;

  // Check if submission succeeded by reading doorbell status
  DoorbellStatus = *(UINT64*(CreateDoorbell.DoorbellStatusCPUVirtualAddress));
  if(DoorbellStatus == D3DDDI_DOORBELL_STATUS_CONNECTED_NOTIFY)
  {
      D3DKMTNotifyWorkSubmission(CreateDoorbell.hDoorbell);
  }

} while (DoorbellStatus == D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY);

KMD에서 초인종 의사 코드 희생

다음 예제에서는 KMD가 전용 초인종을 사용하는 GPU의 HWQueues 간에 사용 가능한 초인종을 "가상화"하고 공유해야 하는 방법을 보여 줍니다.

KMD 함수 VictimizeDoorbell() 의 의사 코드:

  • KMD는 연결된 논리적 초인종 hDoorbell1PhysicalDoorbell1 희생하고 연결을 끊어야 한다고 결정합니다.
  • KMD는 Dxgkrnl을 호출합니다DxgkCbDisconnectDoorbellCB(hDoorbell1->hHwQueue).
    • Dxgkrnl은 이 초인종의 UMD 표시 CPUVA를 더미 페이지로 회전하고 상태 값을 D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY 업데이트합니다.
  • KMD는 제어권을 되돌리고 실제 피해/연결 끊김을 수행합니다.
    • KMD에서 hDoorbell1 피해를 입은 후 연결을 끊습니다 PhysicalDoorbell1.
    • PhysicalDoorbell1 를 사용할 수 있습니다.

이제 다음 시나리오를 고려합니다.

  1. PCI BAR에는 커널 모드 CPUVA가 같은 단일 물리적 초인종이 있습니다 0xfeedfeee. HWQueue에 대해 만든 초인종 개체에는 이 실제 초인종 값이 할당됩니다.

    HWQueue KMD Handle: hHwQueue1
    Doorbell KMD Handle: hDoorbell1
    Doorbell CPU Virtual Address: CpuVirtualAddressDoorbell1 =>  0xfeedfeee // hDoorbell1 is mapped to 0xfeedfeee
    Doorbell Status CPU Virtual Address: StatusCpuVirtualAddressDoorbell1 => D3DDDI_DOORBELL_STATUS_CONNECTED
    
  2. OS는 다른 HWQueue2다음을 요구 DxgkDdiCreateDoorbell 합니다.

    HWQueue KMD Handle: hHwQueue2
    Doorbell KMD Handle: hDoorbell2
    Doorbell CPU Virtual Address: CpuVirtualAddressDoorbell2 => 0 // this doorbell object isn't yet assigned to a physical doorbell  
    Doorbell Status CPU Virtual Address: StatusCpuVirtualAddressDoorbell2 => D3DDDI_DOORBELL_STATUS_DISCONNECTED_RETRY
    
    // In the create doorbell DDI, KMD doesn't need to assign a physical doorbell yet, 
    // so the 0xfeedfeee doorbell is still connected to hDoorbell1
    
  3. OS는 다음을 호출 DxgkDdiConnectDoorbell 합니다.hDoorbell2

    // KMD needs to victimize hDoorbell1 and assign 0xfeedfeee to hDoorbell2. 
    VictimizeDoorbell(hDoorbell1);
    
    // Physical doorbell 0xfeedfeee is now free and can be used vfor hDoorbell2.
    // KMD makes required connections for hDoorbell2 with HW
    ConnectPhysicalDoorbell(hDoorbell2, 0xfeedfeee)
    
    return 0xfeedfeee
    
    // On return from this DDI, *Dxgkrnl* maps 0xfeedfeee to process address space CPUVA i.e:
    // CpuVirtualAddressDoorbell2 => 0xfeedfeee
    
    // *Dxgkrnl* updates hDoorbell2 status to connected i.e:
    // StatusCpuVirtualAddressDoorbell2 => D3DDDI_DOORBELL_STATUS_CONNECTED
    ``
    
    

GPU에서 전역 초인종을 사용하는 경우에는 이 메커니즘이 필요하지 않습니다. 대신, 이 예제에서는 둘 다 hDoorbell1 동일한 hDoorbell20xfeedfeee 실제 초인종을 할당합니다.