MCDM이란 무엇인가
1. MCDM이 무엇인가
MCDM(Microsoft Compute Driver Model)은 디스플레이 출력이 없는 컴퓨트 전용 디바이스를 위해 만들어진 WDDM 2.0 이상의 부분 집합(subset)이다. Windows 10 버전 1903(WDDM 2.6)부터 사용할 수 있다.
MS Learn의 정의:
An MCDM driver, or compute-only driver, is a scaled down subset of Windows Display Driver Model 2.0+ (WDDM). In WDDM terminology, the driver must advertise itself as a “render-only” device without display functionality.
핵심은 두 단어다. “render-only” + “compute-only”. WDDM의 디스플레이 파이프라인 — 모니터 출력, 오버레이, VidPN, 색상 관리 등 — 은 모두 빠지고, GPU/NPU가 받아들일 수 있는 명령 버퍼(command buffer)를 큐에 밀어넣고 실행을 조율하는 골격만 남는다. WDDM이 알고 있는 “render device”의 명령 버퍼 내용은 OS 입장에서 불투명(opaque)하므로, 그 안에 뭐가 들어있든 WDDM은 신경 쓰지 않는다. NPU 명령이든 GPU 컴퓨트 명령이든 똑같이 처리할 수 있다.
2. 왜 KMDF나 WDDM이 아니라 MCDM인가
KMDF로는 부족한 이유. KMDF는 PnP, 전원 관리, I/O 큐, DMA 트랜잭션 같은 일반적 디바이스 드라이버의 패턴을 추상화한다. 하지만 GPU/NPU 같은 가속기에는 KMDF가 제공하지 않는 것이 많이 필요하다.
- 프로세스별 가상 주소 공간(GPU virtual memory)
- 다중 프로세스가 한 디바이스를 공유할 때의 컨텍스트 전환과 스케줄링
- 명령 버퍼(DMA Buffer)의 큐 관리, 우선순위, 선점(preemption)
- 멀티 엔진(예: 컴퓨트 엔진과 카피 엔진을 분리한 디바이스)의 병렬 스케줄링
- TDR(Timeout Detection and Recovery) — 폭주한 디바이스를 OS가 강제로 회복
이 기능들은 모두 WDDM이 이미 갖고 있다. 가속기 드라이버를 위해 KMDF에 다 새로 짜는 건 비효율적이다.
전체 WDDM은 과한 이유. 반대로 WDDM은 디스플레이 파이프라인 전체 — VidPN, 디스플레이 토폴로지 인식, 모드 설정, 오버레이, 포인터, GDI 폴백 등 — 를 의무적으로 구현하라고 요구한다. 모니터에 한 픽셀도 출력하지 않는 NPU에게 그 모든 콜백을 구현하라는 건 의미가 없다.
MCDM은 둘의 중간이다. WDDM의 코어(가상 메모리, 컨텍스트, 스케줄러, 선점, TDR)는 그대로 받고, 디스플레이 부분은 통째로 뺀다. 디바이스 드라이버는 자기가 “compute-only”라고 선언하고, 디스플레이 관련 콜백 수십 개를 구현 면제받는다.
Note
MCDM은 새로운 별개의 모델이 아니라 “WDDM에 ComputeOnly=TRUE 플래그를 켠 상태” 라고 보는 게 정확하다. 같은 Dxgkrnl, 같은 DXGK_DRIVERCAPS 구조체, 같은 DDI 콜백들을 쓴다. 단지 디스플레이 관련 콜백/캡들이 비활성화된다.
3. 드라이버의 구성: KMD + UMD
MCDM 드라이버는 두 부분으로 이루어진다.
- KMD(Kernel-Mode Driver) —
.sys파일. Dxgkrnl이 호출하는 DXGK 콜백들을 구현. 디바이스 초기화, 메모리 관리, 명령 버퍼 제출, 인터럽트 처리, 전원 관리 등 커널 측 모든 일을 담당. - UMD(User-Mode Driver) — DLL. Direct3D 12 / DirectML 같은 사용자 모드 런타임이 로드하여 호출. 사용자 코드에서 들어온 컴퓨트 작업을 KMD에 넘길 수 있는 형태(DDI 호출)로 변환.
INF 파일은 디바이스 클래스를 다음과 같이 선언해야 한다.
[Version]
...
Class=ComputeAccelerator
ClassGuid={F01A9D53-3FF6-48D2-9F97-C8A7004BE10C}
...
ComputeAccelerator 라는 클래스 이름과 위 GUID는 NPU/AI 가속기 드라이버를 식별하는 표준이다. 디바이스 관리자에서 NPU를 보면 이 클래스 아래에 묶여 있다.
4. 아키텍처 — 7가지 핵심 개념
작업이 사용자 코드에서 시작되어 디바이스 위에서 실행되는 흐름은 7가지 개념으로 분해된다. 이 흐름이 MCDM의 본질이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
사용자 작업
↓
[Command Queue] ← DirectCompute의 작업 제출 단위
↓ (드라이버가 DMA Buffer로 변환)
[Context] ← 엔진을 타깃으로 하는 작업 큐 (인스턴스별 상태 보유)
↓
[SW Queue] ← Context마다 1:1로 붙어 있는 소프트웨어 큐
↓ (Scheduler가 꺼내서 제출)
[Engine] ← 실제 명령 실행. 디바이스가 여러 엔진을 가질 수 있음
↓
[HW Queue] ← Engine 앞에 붙은 하드웨어 큐 (현재 최대 2개 항목)
↓
실행 + 완료 알림
- Command Queue. D3D12/DirectCompute의 작업 제출 추상. 사용자 코드는 여기에 작업을 넣는다.
- Context. 특정 엔진을 타깃으로 하는 컴퓨트 작업의 큐. 각 Context는 자신의 인스턴스별 상태를 가진다(예: 어떤 페이지 테이블을 쓸 것인가, 어떤 우선순위인가).
- DMA Buffer. 드라이버가 DDI 호출을 변환해 만들어내는 명령의 묶음. 엔진이 한 단위로 받아 실행. 호스트 메모리에 위치하며 디바이스가 DMA로 직접 읽어가는 일반적인 DMA 버퍼와 같은 종류이지만, 그 안에 들어있는 내용이 디바이스 명령(컴퓨트 셰이더 디스패치, 데이터 이동 등)이라는 점이 다르다.
- SW Queue. Context와 1:1로 붙어 있는 소프트웨어 큐. 길이는 자원만큼만 제한.
- Scheduler. OS가 구현하며, 드라이버는 관여할 수 없다. 여러 Context의 SW Queue들 사이에서 공정성을 유지하고, 우선순위가 높은 작업이 적시에 완료되도록 선점(preempt)도 수행한다.
- Engine. 명령을 실제로 실행하는 하드웨어. 한 디바이스에 여러 엔진이 있을 수 있다(예: 메인 컴퓨트 엔진 + 별도 카피 엔진). 엔진들끼리는 서로 막지 않고 독립적으로 진행할 수 있어야 한다. 단, 다중 엔진을 지원하려면 각 엔진이 독립적으로 Address Space를 전환할 수 있어야 한다. 즉, 한 엔진이 P1 프로세스의 작업을 처리하는 동안 다른 엔진이 P2 프로세스의 작업을 동시에 처리할 수 있어야 멀티 엔진 디바이스로 인정된다.
- HW Queue. 엔진 앞에 붙은 작은 하드웨어 큐. 현재 사양으로는 최대 2개의 DMA Buffer만 들어간다. 엔진은 도착 순서대로 완료해야 한다.
Note
여기서 말하는 “HW Queue”는 Implementation Guidelines의 Hardware scheduling support 섹션에 등장하는 HW Queue(DxgkDdiCreateHwQueue, DxgkDdiSubmitCommandToHwQueue 등)와는 다른 개념이다. 전자는 모든 MCDM 드라이버에 적용되는 엔진 앞단의 추상이고, 후자는 WDDM 2.7+의 하드웨어 가속 GPU 스케줄링 이라는 옵션 기능이 켜진 경우에만 등장한다. 후자에서는 OS의 SW Queue를 거치지 않고 디바이스 자체가 명령 큐를 관리한다.
4-1. 선점(preemption) — 컴퓨트 가속기에서 특히 중요한 이유
엔진은 반드시 선점을 지원해야 한다. 작업이 너무 오래 걸리거나 더 높은 우선순위 작업이 들어오면, OS는 현재 실행 중인 DMA Buffer를 중단할 수 있어야 한다. 부분적으로 실행된 버퍼는 나중에 재개할 수 있도록 충분한 정보를 드라이버가 저장해 두어야 한다.
이는 NPU에서 특히 까다로운 요구다. 한 번 시작하면 수백 ms~수 초가 걸리는 거대한 모델 추론을 처리하다가 갑자기 사용자가 더 작고 긴급한 작업(예: Copilot 응답)을 띄우면, NPU는 그 큰 작업을 중단하고 작은 작업을 끼워 넣었다가 다시 돌아와야 한다. 하드웨어 설계 시점부터 선점 단위(preemption granularity)를 결정해야 한다는 뜻이다.
4-2. Address Space — 프로세스별 디바이스 주소 공간
각 호스트 측 프로세스는 자기만의 Address Space 를 가진다. 이는 디바이스 측 가상 주소를 디바이스 측 물리 주소로 매핑하는 페이지 테이블의 묶음이다.
엔진은 여러 프로세스가 공유하므로, DMA Buffer를 실행할 때마다 적절한 Address Space로 전환할 수 있어야 한다. Address Space 전환은 단지 루트 페이지 테이블 포인터를 바꾸는 것이다.
Important
이 페이지 테이블은 시스템의 IOMMU(또는 디바이스 자체 GPU-MMU)가 들고 있는 페이지 테이블과 같은 것이다. 즉, MCDM의 Address Space = 그 프로세스를 위해 IOMMU/GPU-MMU가 들고 있는 페이지 테이블 도메인. 선점, 컨텍스트 전환, 보안 — 거의 모든 핵심 기능이 이 구조 위에서 작동한다.
5. MMU 요구사항
MCDM 사양은 디바이스에 MMU가 있어야 한다고 명시한다. 디바이스가 시스템 메모리에 접근할 때 물리 주소를 직접 못 쓰고 가상 주소를 통해야 한다는 뜻이다. 다음 두 가지 중 하나만 있으면 충족된다. 둘 다 갖출 필요는 없다.
- IOMMU — 시스템 칩셋의 IOMMU(VT-d, AMD-Vi, ARM SMMU)를 통해 디바이스 가상 주소 → 물리 주소 변환.
IoMmuSupported캡으로 선언. - GPU-MMU — 디바이스 자체에 내장된 MMU.
GpuMmuSupported캡으로 선언.
드라이버는 가상 주소 지정을 사용한다는 사실을 MemoryManagementCaps.VirtualAddressingSupported로 켠 다음, 위 두 캡 중 하나(또는 둘 다)를 함께 켜야 한다. 둘 다 꺼져 있으면 정식 MCDM이 아니라 아래 예외에 해당하는 Single Use 디바이스가 된다.
이 요구사항이 있는 이유는 악의적인 프로세스의 존재 하에서 멀티태스킹을 안전하게 지원하기 위해서이다. 즉, A 프로세스가 NPU에 작업을 넣을 때 우연히든 고의로든 B 프로세스의 메모리를 건드리지 못하도록 디바이스 측에서 격리되어야 한다. MMU 없이는 이를 보장할 수 없다.
Note
예외: Windows 10 버전 2004부터 프로토타입용으로 MMU가 없는 MCDM 디바이스도 인정한다(IOMMU·GPU-MMU 둘 다 부재). 단 이 경우 디바이스는 한 번에 하나의 프로세스만 사용할 수 있다(Single Use device). 양산 NPU에서는 사실상 적용되지 않는 예외다.
Important
IoMmuSupported를 켠다는 것은 단순히 “IOMMU가 있다”가 아니라 “디바이스가 CPU와 페이지 테이블을 공유한다(SVM, shared virtual memory)” 를 의미한다(MS Learn 명시). 이 모델에서는 호스트와 디바이스가 같은 페이지 테이블을 공유하므로, 호스트 측 가상 주소를 디바이스에 그대로 넘겨도 동일한 물리 메모리를 가리킨다. 호스트와 디바이스 사이의 포인터 전달이 별도의 매핑 단계 없이 자연스러워진다.
6. 드라이버 진입과 핵심 capability flags
MCDM 드라이버의 DriverEntry는 다음과 같이 시작한다.
DRIVER_INITIALIZATION_DATA구조체를 할당하고 채운다. 여기에 자신이 구현한 DXGK 콜백 함수 포인터들을 모두 등록한다.DxgkInitialize를 호출한다. (KMDF의WdfDriverCreate에 해당하는, MCDM/WDDM 측의 진입점이다.)
주요 capability flags는 다음과 같다.
최상위 DXGK_DRIVERCAPS:
| 멤버 | MCDM 요구값 |
|---|---|
WDDMVersion | DXGKDDI_WDDMv2_6 이상 |
ComputeOnly | TRUE (필수) — 이 한 비트가 디바이스를 “compute-only”로 식별한다 |
SupportPerEngineTDR | TRUE (필수) |
HybridDiscrete / HybridIntegrated | 둘 다 FALSE (필수) |
PreemptionCaps.GraphicsPreemptionGranularity | 하드웨어가 지원하는 수준에 맞게. 최소 packet-level. |
PreemptionCaps.ComputePreemptionGranularity | D3DKMDT_COMPUTE_PREEMPTION_NONE 외의 값으로 설정. 즉 컴퓨트 선점은 반드시 지원. |
MaxOverlays, PointerCaps, GammaRampCaps, PresentationCaps, SupportNonVGA, SupportDirectFlip, SupportMultiPlaneOverlay, FlipCaps, … | 모두 0 또는 FALSE (디스플레이 기능 비활성화) |
SchedulingCaps 하위 멤버:
| 멤버 | MCDM 요구값 |
|---|---|
MultiEngineAware | TRUE (필수) — 단일 엔진 디바이스라도 켜야 한다. |
PreemptionAware | TRUE (필수) |
LowIrqlPreemptCommand | TRUE (필수) — OS는 DxgkDdiPreemptCommand를 low IRQL에서 호출한다는 약속. |
VSyncPowerSaveAware | FALSE (디스플레이 관련) |
NoDmaPatching | FALSE |
MemoryManagementCaps 하위 멤버:
| 멤버 | MCDM 요구값 |
|---|---|
VirtualAddressingSupported | 가상 주소 지정을 사용함. 켜면 GpuMmuSupported나 IoMmuSupported 중 하나(또는 둘 다)도 켜야 한다. |
GpuMmuSupported | 디바이스에 자체 MMU가 있으면 TRUE. |
IoMmuSupported | 시스템 IOMMU를 통해 CPU와 페이지 테이블을 공유(SVM)하면 TRUE. |
IoMmuSecureModeSupported | 디바이스가 IOMMU 격리(전용 페이지 테이블)를 지원하면 TRUE. FALSE면 Windows Sandbox/MDAG 같은 보안 VM 안에서는 사용 불가. |
ParavirtualizationSupported | GPU-P/SR-IOV 호스트 드라이버는 FALSE, 그 외(물리 머신 드라이버 또는 GPU-P 통해 노출된 vGPU의 게스트 드라이버)는 TRUE. |
또한 DxgkDdiQueryAdapterInfo를 통해 OS가 다양한 정보 타입(DXGKQAITYPE_DRIVERCAPS, DXGKQAITYPE_QUERYSEGMENT4, GPU VA를 지원하면 DXGKQAITYPE_GPUMMUCAPS와 DXGKQAITYPE_PAGETABLELEVELDESC 등)을 조회할 수 있어야 한다.
7. 사용자 모드 측: D3D12 Core 1.0 Feature Level
UMD 측에서 MCDM 디바이스가 노출하는 사용자 API는 Direct3D 12의 Core 1.0 Feature Level 이다. 이는 D3D12의 컴퓨트 관련 부분만 골라낸 최소 집합으로, 그래픽 파이프라인을 의미하는 모든 것(레스터화, 픽셀 셰이더 등)이 빠져 있다.
이 위에서 다음 라이브러리들이 동작한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
Application (Python 등)
↓
ONNX Runtime / Windows ML
↓
DirectML
↓
Direct3D 12 (Core 1.0 Feature Level)
↓
Dxgkrnl (graphics/compute kernel)
↓
MCDM KMD (vendor driver)
↓
NPU hardware
NPU 벤더 입장에서 MCDM KMD를 구현하면, 위의 모든 상위 레이어가 자동으로 그 디바이스를 인식하고 사용할 수 있게 된다. 따로 파이썬 라이브러리를 만들 필요 없이, ONNX Runtime이 DirectML EP를 통해 NPU에서 모델을 돌릴 수 있다.
8. NPU에 적용할 때 결정해야 할 것들
MS Learn은 MCDM의 골격까지만 정의한다. 실제 NPU 드라이버 구현 시 벤더가 결정해야 할 항목들:
- 명령 버퍼 포맷. OS는 DMA Buffer 안의 내용을 모른다. NPU가 직접 해석할 수 있는 명령 인코딩을 정의해야 한다. UMD가 D3D12/DML 호출을 이 인코딩으로 변환한다.
- 선점 단위(preemption granularity). 모델 추론 한 번이 한 DMA Buffer라면 선점이 거칠 것이다. 더 작은 단위(레이어 단위, 텐서 타일 단위)로 자를 수 있도록 하드웨어/드라이버를 설계해야 한다.
- 엔진 분리. 컴퓨트 엔진과 카피 엔진을 분리할지, 단일 엔진으로 갈지. 분리하면 데이터 전송과 컴퓨트가 병렬화되지만 멀티 Address Space 지원이 필요해진다.
- TDR 정책. 너무 오래 걸리는 작업을 OS가 강제 중단할 때, 어떤 상태에서 회복할 수 있어야 하는가. NPU는 보통 매우 긴 작업을 다루므로 기본 TDR 타임아웃을 늘려야 할 수 있다.
- 하드웨어 가속 스케줄링(WDDM 2.7+) 채택 여부. Implementation Guidelines의 Hardware scheduling support 섹션은 옵션이다. 활성화하면 OS의 SW Queue / Scheduler 경로를 우회하고, 디바이스 자체가 명령 큐를 관리하면서 OS는
DxgkDdiSubmitCommandToHwQueue로 디바이스의 HW Queue에 직접 명령을 제출한다. 관련 콜백:DxgkDdiCreateHwContext,DxgkDdiCreateHwQueue,DxgkDdiSwitchToHwContextList,DxgkDdiSetContextSchedulingProperties등 10여 개. NPU에서 채택하면 추론 작업 제출 오버헤드를 줄일 수 있지만, 디바이스 측에 컨텍스트 전환·우선순위·페이지 폴트 처리 로직을 모두 구현해야 한다. Copilot+ 등급의 always-on AI 워크로드에서 가치가 가장 크다. - 메모리 세그먼트 모델. 디바이스 로컬 메모리(있다면)와 시스템 메모리를 어떻게 세그먼트로 노출할지. WDDM의
DXGKQAITYPE_QUERYSEGMENT4를 통해 OS에 보고. - 전원 관리. 유휴 시 전력 소비, D3 진입/탈출 지연. Copilot+ PC처럼 NPU가 항상 켜져 있는 환경에서 특히 중요.
9. 벤더 채택 패턴
NPU/AI 가속기 벤더가 Windows 드라이버를 만들 때의 선택지는 일반적으로 셋이다.
- MCDM을 채택해 작성 — Windows 표준 경로. 위에서 정리한 모든 내용이 그대로 적용된다.
- 자체 KMDF 기반 드라이버 + 자체 사용자 모드 런타임 — 일찍 시작했거나 OS와 결합도를 낮추고 싶은 경우. MCDM의 아키텍처(컨텍스트, 큐, 선점, IOMMU 활용)를 자체적으로 다시 구현하게 된다.
- 혼합 — 초기에는 KMDF로 빠르게, 추후 MCDM으로 마이그레이션. 또는 데이터 평면은 자체 구현, 제어 평면만 MCDM.
어떤 경로를 택하든, NPU는 OS의 표준 컴퓨트 인프라(스케줄러, 가상 메모리, 선점, TDR)와 어떻게든 어울려야 한다. MCDM은 그 어울림을 표준화한 한 가지 답이다.
출처
참고한 Microsoft Learn 페이지들:
- Microsoft Compute Driver Model overview — MCDM의 한 줄 정의, 도입 버전, MMU 요구사항, 프로토타입 예외
- MCDM architecture — Command Queue / Context / SW Queue / Scheduler / Engine / HW Queue / DMA Buffer / Address Space / Preemption
- MCDM kernel-mode driver implementation guidelines — INF 클래스, DriverEntry, DXGK_DRIVERCAPS 요구값, Query adapter info 타입
- Developer documentation for display, graphics, and compute accelerator drivers — WDDM/MCDM/XDDM의 위치 정리
- The Direct3D 12 Core 1.0 Feature Level — UMD 측 사용자 API 면적
더 깊이 다루는 자료:
- Microsoft BUILD/Ignite 세션 녹화 — DirectML, Windows ML, NPU 관련 세션. MS Learn보다 NPU 관점이 더 또렷한 경우가 많다.
- 벤더 SDK 문서 — Qualcomm QNN, Intel NPU SDK, AMD Ryzen AI SDK. 각 벤더가 실제로 어떻게 MCDM 위에 자기 런타임을 얹었는지를 보여 준다.
- ONNX Runtime의 DirectML execution provider 코드 —
microsoft/onnxruntime저장소. 사용자 모드 측에서 DML을 통해 MCDM 디바이스를 어떻게 다루는지의 실제 사례. - WDDM 그래픽 가이드 — MCDM은 WDDM의 부분 집합이므로, 디스플레이 부분을 빼고 읽으면 그대로 MCDM 이해에 적용된다.