DRM 코어 및 디스플레이 (KMS)

Linux DRM(Direct Rendering Manager) 코어 아키텍처와 KMS(Kernel Mode Setting) 디스플레이 파이프라인을 심층 분석합니다. DRM 디바이스 노드와 권한 모델, KMS 객체(CRTC/plane/encoder/connector), atomic modesetting, DRM properties, VRR(Variable Refresh Rate), format modifier, DRM bridge/panel, 디스플레이 연결 프로토콜, HDCP content protection, DRM lease, fbdev 에뮬레이션, 주요 오픈소스 DRM 드라이버 구조를 다룹니다.

전제 조건: GPU 서브시스템 개요 페이지에서 DRM/KMS 전체 구조를 먼저 파악하세요. GPU 메모리 관리와 스케줄링은 GPU 메모리 관리 및 스케줄러 페이지를 참고하세요.

DRM (Direct Rendering Manager) 개요

DRM은 Linux 커널의 GPU 접근을 관리하는 서브시스템입니다. 원래 3D 그래픽 가속을 위해 도입되었으나, 현재는 디스플레이 출력(KMS), GPU 메모리 관리(GEM/TTM), GPU 작업 스케줄링까지 포괄하는 핵심 프레임워크로 발전했습니다.

구성 요소역할커널 코드
DRM Core 드라이버 등록(Driver Registration), ioctl 디스패치(Dispatch), 파일 오퍼레이션 drivers/gpu/drm/drm_*.c
KMS (Kernel Mode Setting) 디스플레이 모드 설정, CRTC/Encoder/Connector/Plane drivers/gpu/drm/drm_atomic*.c
GEM (Graphics Execution Manager) GPU 메모리 버퍼 할당/관리, mmap drivers/gpu/drm/drm_gem*.c
TTM (Translation Table Manager) VRAM/시스템 메모리 간 버퍼 이동, 페이징 drivers/gpu/drm/ttm/
DMA-BUF 디바이스 간 버퍼 공유 (GPU↔카메라↔디스플레이) drivers/dma-buf/
GPU Scheduler GPU 작업 큐(Workqueue) 관리, 우선순위(Priority), 타임아웃 처리 drivers/gpu/drm/scheduler/
DRM vs fbdev: fbdev(drivers/video/fbdev/)는 단순 프레임버퍼만 제공하는 레거시 인터페이스입니다. DRM/KMS는 하드웨어 가속, 다중 디스플레이, vsync, overlay plane 등을 지원하며, fbdev는 DRM으로 대체되는 추세입니다. 메인라인 그래픽 드라이버 개발에서는 DRM/KMS 사용이 권장되며 사실상 표준 경로입니다.

디바이스 노드와 권한 모델

현대 DRM UAPI는 GPU 하나를 단일 문자 디바이스로만 노출하지 않습니다. 같은 하드웨어라도 화면 제어, 비특권 렌더링, 비그래픽 연산을 서로 다른 노드로 나누어 권한 경계와 사용자 공간(User Space) 스택을 분리합니다. 이 구분을 이해하지 못하면 drm_file의 인증 상태, client capability, 버퍼 공유 규칙, compositor와 compute runtime의 역할이 한꺼번에 흐려집니다.

노드 종류대표 경로주 용도권한/제약
Primary /dev/dri/card0 KMS modeset, connector/plane/lease 제어, 레거시 ioctl DRM master 개념이 존재합니다. 보통 compositor, Xorg, display manager가 소유합니다.
Control /dev/dri/controlD64 과거 KMS 제어용으로 설계됨 메인라인 문서 기준으로 현재는 사실상 미사용입니다.
Render /dev/dri/renderD128 OpenGL/Vulkan/VA-API/OpenCL 등 비특권 렌더링과 GPGPU modeset 및 privileged ioctl 불가. DRM master 없이 열 수 있으며 PRIME 기반 공유가 중심입니다.
Accel /dev/accel/accel0 NPU/AI/신호 처리 같은 비그래픽 compute DRIVER_COMPUTE_ACCEL 전용 네임스페이스(Namespace)입니다. graphics 스택과 분리된 별도 major를 사용합니다.
Compositor / Display Server Mutter, KWin, Weston KMS atomic commit, lease, hotplug 3D / Media Client Mesa, Vulkan, VA-API, OpenCL 비특권 렌더링, offscreen, compute AI / NPU Runtime vendor UMD, inference runtime 비그래픽 명령 제출, buffer mapping Primary Node /dev/dri/card0 DRM master + KMS Render Node /dev/dri/renderD128 no modeset, no master Accel Node /dev/accel/accel0 compute-only namespace 공통 커널 인프라 GEM/TTM, DMA-BUF, dma_resv, syncobj, scheduler, GPUVM
/* 유저 공간은 node 종류와 client capability를 먼저 협상합니다 */
int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
drmSetClientCap(fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);

/* para-virtual GPU에서는 커서 plane hotspot capability가 추가로 필요할 수 있습니다 */
drmSetClientCap(fd, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT, 1);
실무 해석: compositor는 대개 primary node에서 KMS를 소유하고, 앱이나 미디어 스택은 render node를 따로 열어 커맨드를 제출합니다. atomic capability를 켜면 drm_file.atomicdrm_file.universal_planes가 함께 의미를 가지며, writeback connector는 atomic 지원 위에 추가로 opt-in 해야 노출됩니다.

DRM 아키텍처

User Space Mesa / Vulkan libdrm Wayland / X11 GPGPU (OpenCL) V4L2 / GBM ioctl / mmap DRM Core /dev/dri/card0 (Primary) & /dev/dri/renderD128 (Render) KMS (Mode Setting) CRTC · Encoder · Connector · Plane GEM / TTM 메모리 관리 GPU Scheduler Job Queue · Fence · Timeout DMA-BUF DRM Driver (i915 / amdgpu / nouveau / panfrost / virtio-gpu ...) 드라이버별 HW 초기화, 커맨드 서브미션, IRQ, 전원 관리 MMIO / DMA GPU Hardware

유저 공간 그래픽 스택

DRM/KMS 위에서 동작하는 유저 공간 소프트웨어 스택의 구조입니다. 각 계층이 DRM을 어떻게 활용하는지 이해하면 전체 그래픽 파이프라인을 파악할 수 있습니다.

계층구성 요소DRM 사용 방식
애플리케이션 게임, 브라우저, 3D 뷰어 OpenGL/Vulkan API 호출 (직접 DRM 접근 안 함)
윈도우 시스템 Wayland compositor (Mutter, KWin, Weston) Primary node에서 KMS atomic commit 수행. 렌더링은 GBM + render node 또는 드라이버 전용 UAPI를 함께 사용
GL/VK 드라이버 Mesa (radeonsi, iris, panfrost, radv, anv) Render node로 GPU 커맨드 제출. 드라이버 고유 ioctl 사용
libdrm DRM ioctl 래퍼 라이브러리 DRM ioctl을 C 함수로 래핑 (drmModeAtomicCommit() 등)
GBM (Generic Buffer Manager) Mesa 제공, compositor용 버퍼 할당 gbm_bo_create()가 드라이버 backend를 통해 scanout/texture/render target용 BO를 생성. dumb buffer는 이보다 훨씬 제한적인 최소 경로
EGL / WSI GL 컨텍스트 관리 / Vulkan Window System Integration DMA-BUF로 렌더 결과를 compositor에 전달
Mesa 드라이버 이름 매핑(Mapping):
  • Intel: GL=iris(Gen8+)/crocus(Gen4~7), Vulkan=anv
  • AMD: GL=radeonsi(GCN+), Vulkan=radv
  • ARM Mali: GL=panfrost(Midgard/Bifrost)/lima(Utgard), Vulkan=panvk
  • Qualcomm: GL/Vulkan=freedreno/turnip
  • Broadcom: GL=v3d(Pi4/5)/vc4(Pi0~3), Vulkan=v3dv

DRM 핵심 구조체(Struct)

DRM 핵심 구조체 관계도 drm_device GPU 디바이스 1개 = drm_device 1개 /dev/dri/card0, /dev/dri/renderD128 drm_driver 드라이버 오퍼레이션 정의 driver_features, fops, ioctls driver * drm_file 프로세스별 open() 인스턴스 filp->private_data 마스터/인증 상태 관리 filelist (1:N) idr (GEM 핸들 테이블) handle → drm_gem_object 매핑 KMS (Mode Setting) 오브젝트들 mode_config drm_crtc 디스플레이 파이프라인 스캔아웃 타이밍 제어 drm_encoder 신호 인코딩 TMDS/LVDS/DSI/eDP drm_connector 물리 출력 포트 HDMI/DP/VGA/DSI drm_plane 이미지 레이어 Primary/Cursor/Overlay drm_framebuffer GEM BO 래퍼 format/modifier/pitches drm_property 속성 (Atomic 상태) rotation/alpha/zpos... GEM BO 참조

drm_device & drm_driver

drm_device는 하나의 GPU 디바이스를 나타내고, drm_driver는 해당 GPU 유형의 오퍼레이션을 정의합니다.

#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>

/* DRM 드라이버 정의 — 드라이버 전체에 하나 */
static const struct drm_driver my_gpu_driver = {
    .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
                          DRIVER_RENDER,
    /* GEM 오퍼레이션 */
    .gem_prime_import   = drm_gem_prime_import,
    .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table,

    /* DRM ioctl 테이블 (드라이버 고유 ioctl) */
    .ioctls             = my_gpu_ioctls,
    .num_ioctls         = ARRAY_SIZE(my_gpu_ioctls),

    /* /sys, /dev 노드 이름 */
    .name               = "my-gpu",
    .desc               = "My GPU DRM driver",
    .date               = "20260101",
    .major              = 1,
    .minor              = 0,

    .fops               = &my_gpu_fops,
};

drm_file (파일 프라이빗)

유저 프로세스(Process)가 DRM/accel 노드를 open하면 drm_file 구조체가 생성됩니다. 이 구조체는 “프로세스별 GPU 컨텍스트”라기보다 파일 디스크립터별 세션 상태에 가깝고, 인증 여부, master 여부, client capability, 핸들 테이블, 이벤트 큐를 함께 들고 있습니다.

/* drm_file 핵심 필드 발췌 (include/drm/drm_file.h) */
struct drm_file {
    bool               authenticated; /* 레거시 primary 노드 렌더 권한 */
    bool               universal_planes;
    bool               atomic;
    bool               writeback_connectors;
    bool               is_master;
    bool               supports_virtualized_cursor_plane;
    struct drm_minor   *minor;        /* primary/render/accel 중 어떤 노드를 열었는지 */
    struct idr         object_idr;    /* GEM 핸들 → drm_gem_object 매핑 */
    struct idr         syncobj_idr;   /* drm_syncobj 핸들 테이블 */
    struct list_head   pending_event_list;
    struct list_head   event_list;    /* vblank, page flip, out-fence 이벤트 */
    void              *driver_priv;   /* 드라이버별 프라이빗 데이터 */
};
authenticated 해석 주의:
  • primary node에서는 master/authentication이 여전히 의미가 있습니다. KMS 관련 많은 ioctl은 현재 master를 전제로 합니다.
  • render node는 modeset/global ioctl을 막고 DRM master 개념도 버립니다. 파일 권한만 맞으면 즉시 GPU 접근이 가능합니다.
  • accel node는 graphics stack과 구분된 compute 전용 경로이므로, display 관련 상태를 노출하지 않는 것이 설계 목표입니다.
DRIVER_RENDER를 설정한 드라이버만 render node를 만들고, DRIVER_COMPUTE_ACCEL는 별도 accel 네임스페이스를 사용합니다.

KMS (Kernel Mode Setting)

KMS는 커널에서 디스플레이 모드를 설정하는 프레임워크입니다. 기존의 유저 공간 모드 설정(UMS)과 달리, 커널이 직접 해상도/주사율/디스플레이 파이프라인을 제어하여 콘솔↔그래픽 전환 시 깜박임이 없고 다중 모니터를 안정적으로 관리합니다.

KMS 핵심 오브젝트

Framebuffer drm_framebuffer GEM 객체 참조 Plane drm_plane Primary / Overlay / Cursor CRTC drm_crtc 스캔아웃 + 타이밍 생성 감마/CTM Encoder drm_encoder 신호 변환 Connector drm_connector HDMI/DP/eDP EDID 읽기 Framebuffer GEM 객체를 감싸는 래퍼. 픽셀 포맷, stride, 오프셋 정보 보유. 여러 Plane에서 공유 가능. Plane (Primary / Overlay / Cursor) 프레임버퍼를 화면 위 특정 위치/크기로 배치. Primary는 필수, Overlay/Cursor는 하드웨어 지원 시 사용. CRTC (CRT Controller) Plane들을 합성하여 최종 프레임 생성. 수직/수평 타이밍(해상도/주사율) 관리. 감마 보정, 색 변환 매트릭스(CTM) 적용. Encoder → Connector Encoder: 디지털 신호를 HDMI/DP/LVDS 등으로 변환. Connector: 물리 포트 + EDID 모니터 정보 + 핫플러그 이벤트.
KMS 오브젝트구조체주요 콜백(Callback)역할
CRTC drm_crtc atomic_check, atomic_flush, atomic_enable 스캔아웃 엔진. 해상도/주사율 타이밍 생성, Plane 합성
Encoder drm_encoder atomic_check, atomic_enable, atomic_disable 내부 디지털 신호를 외부 프로토콜(HDMI/DP)로 변환
Connector drm_connector detect, get_modes, atomic_check 물리적 출력 포트. EDID 파싱, 핫플러그(Hotplug) 감지
Plane drm_plane atomic_check, atomic_update, atomic_disable 프레임버퍼를 화면에 배치. 스케일링, 회전, 블렌딩
Framebuffer drm_framebuffer create_handle, destroy GEM 객체 래퍼. 픽셀 포맷, stride, modifier 정보

Vblank 처리와 페이지(Page) 플립

Vblank(수직 귀선 기간)은 디스플레이가 한 프레임을 마치고 다음 프레임을 시작하기 직전의 시간 구간입니다. 이 시점에 프레임버퍼를 교체(page flip)해야 화면 찢어짐(tearing)이 발생하지 않습니다. DRM 코어는 drm_vblank 인프라로 정확한 vblank 타이밍과 시퀀스 번호를 관리합니다.

/* Vblank 관련 드라이버 콜백 */
static const struct drm_crtc_funcs my_crtc_funcs = {
    /* vblank 카운터/타임스탬프 제공 */
    .get_vblank_counter  = drm_crtc_vblank_count,
    .enable_vblank       = my_enable_vblank,   /* vblank IRQ 활성화 */
    .disable_vblank      = my_disable_vblank,  /* vblank IRQ 비활성화 */
    .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
};

/* 드라이버 vblank IRQ 핸들러 */
static irqreturn_t my_irq_handler(int irq, void *data)
{
    struct drm_device *dev = data;
    u32 status = readl(regs + IRQ_STATUS);

    if (status & VBLANK_IRQ) {
        drm_crtc_handle_vblank(&my_crtc);  /* vblank 카운터 증가 + 이벤트 전달 */
    }
    return IRQ_HANDLED;
}

/* 페이지 플립 완료 알림 (vblank IRQ에서 호출) */
if (page_flip_pending) {
    drm_crtc_send_vblank_event(&my_crtc, event);
    drm_crtc_vblank_put(&my_crtc);
    page_flip_pending = false;
}
함수역할호출 위치
drm_crtc_vblank_on()CRTC 활성화 시 vblank 추적 시작CRTC enable 콜백
drm_crtc_vblank_off()CRTC 비활성화 시 vblank 추적 중단CRTC disable 콜백
drm_crtc_vblank_get()vblank IRQ 참조 획득 (카운팅)페이지 플립 요청 시
drm_crtc_vblank_put()vblank IRQ 참조 해제플립 완료 후
drm_crtc_handle_vblank()vblank 카운터 증가, 대기 중인 이벤트 처리vblank IRQ 핸들러(Handler)
drm_crtc_send_vblank_event()유저에게 페이지 플립 완료 이벤트 전달플립 완료 시점
정밀 vblank 타임스탬프: drm_crtc_vblank_helper_get_vblank_timestamp()는 하드웨어 스캔라인 카운터를 읽어 vblank의 정확한 시각을 계산합니다. 이 타임스탬프는 DRM_EVENT_FLIP_COMPLETE 이벤트에 포함되어 유저 공간(Wayland compositor 등)이 프레임 타이밍을 정밀하게 제어하는 데 사용됩니다. 고정밀 프레임 스케줄링의 핵심 인프라입니다.

Atomic Modesetting

Atomic modesetting은 KMS의 현대적 커밋 모델입니다. 여러 디스플레이 속성 변경을 하나의 원자적(Atomic) 트랜잭션(Transaction)으로 묶어 중간 상태 없이 적용하거나 전체를 롤백(Rollback)합니다.

Atomic 상태 객체 그래프

실제 atomic UAPI의 핵심은 “property를 바로 레지스터(Register)에 쓰는 것”이 아니라, drm_atomic_state 아래에 CRTC/plane/connector/private object의 새 상태를 모아 둔 뒤 한 번에 검증하고 커밋하는 것입니다. driver의 atomic_check는 이 그래프 전체를 보고 대역폭(Bandwidth), scaler 수, watermark, 링크 훈련 가능 여부, color LUT 크기, writeback 출력 버퍼 충돌까지 판단합니다.

상태 객체대표 구조체주요 내용
트랜잭션 컨테이너(Container) drm_atomic_state 이번 커밋에서 바뀌는 모든 object의 old/new state 포인터와 acquire context를 묶습니다.
CRTC 상태 drm_crtc_state mode, active 여부, color pipeline, vrr, out-fence, bandwidth 결과를 담습니다.
Plane 상태 drm_plane_state framebuffer, source/destination rectangle, rotation, zpos, in-fence를 담습니다.
Connector 상태 drm_connector_state 연결된 CRTC, link status, colorspace, writeback job, content protection 상태를 담습니다.
드라이버 private 상태 drm_private_obj 계열 watermark, shared DPLL, DSC slice allocator처럼 여러 오브젝트가 공유하는 HW 자원을 모델링합니다.
drm_atomic_state 이번 커밋의 old/new 상태 묶음 drm_crtc_state mode, active, vrr, color bandwidth / out-fence drm_plane_state fb, src/dst rect, zpos rotation / in-fence drm_connector_state link status, colorspace writeback / content protection private obj state watermark, DPLL, DSC shared HW allocator atomic_check → atomic_commit 검증 단계는 그래프 전체를 보고 실패 시 폐기, 성공 시 commit tail에서 HW 순서대로 적용
/* Atomic 커밋 흐름 (커널 내부) */

/* 1. 유저가 DRM_IOCTL_MODE_ATOMIC 호출 */
/*    → drm_mode_atomic_ioctl() 진입 */

/* 2. 상태 복제 */
struct drm_atomic_state *state = drm_atomic_state_alloc(dev);
/* 각 오브젝트의 현재 상태를 복제하여 new_state 생성 */

/* 3. 속성 적용 (유저가 요청한 변경사항) */
drm_atomic_set_crtc_for_connector(new_conn_state, crtc);
new_crtc_state->mode_blob = mode;
new_plane_state->fb = framebuffer;
new_plane_state->crtc = crtc;

/* 4. 검증 (atomic_check) — 하드웨어 제약 확인 */
ret = drm_atomic_check_only(state);
/* 각 CRTC/Plane/Connector의 atomic_check 콜백 호출 */
/* 실패 시 -EINVAL 반환, 유저에게 거부 통보 */

/* 5. TEST_ONLY 플래그면 여기서 종료 (검증만 수행) */
if (flags & DRM_MODE_ATOMIC_TEST_ONLY)
    return ret;

/* 6. 커밋 (atomic_commit) — 실제 하드웨어 적용 */
ret = drm_atomic_commit(state);
/* NONBLOCK 플래그: 비동기 커밋 (vsync 대기 안 함) */
/* PAGE_FLIP_EVENT: 완료 시 유저에게 이벤트 전달 */
Atomic Modesetting 커밋 상태 머신 User IOCTL 요청 State 복제(Dup) Property 값 설정 atomic_check HW 제약 검증 실패 Rollback 상태 폐기 성공 TEST ONLY? Yes Return 0 검증 완료 No Commit atomic_commit HW Apply 레지스터 적용 Fence/Event FLIP_COMPLETE 범례: 성공 경로 (검증 통과 → 커밋) 실패 경로 (검증 실패 → 롤백) TEST_ONLY 경로 (검증만 수행)
Atomic 커밋 플래그:
  • DRM_MODE_ATOMIC_TEST_ONLY — 검증만 수행, 실제 적용 안 함. 유저 공간에서 구성 유효성을 미리 확인
  • DRM_MODE_ATOMIC_NONBLOCK — 비동기 커밋. vsync을 기다리지 않고 즉시 반환
  • DRM_MODE_PAGE_FLIP_EVENT — 플립 완료 시 DRM_EVENT_FLIP_COMPLETE 이벤트를 유저에게 전달
  • DRM_MODE_ATOMIC_ALLOW_MODESET — 해상도/주사율 변경이 포함된 full modeset 허용

DRM Properties 시스템

KMS 오브젝트(CRTC, Plane, Connector)의 모든 설정 가능한 속성은 DRM Property로 표현됩니다. Atomic modesetting에서는 property ID와 값을 쌍으로 전달하여 디스플레이 상태를 변경합니다.

Property 타입

타입커널 생성 함수값 형태예시
Range drm_property_create_range() min~max 정수 alpha (0~0xFFFF), rotation angle
Enum drm_property_create_enum() 이름↔값 열거 DPMS (On/Standby/Suspend/Off)
Bitmask drm_property_create_bitmask() 비트 조합 rotation (ROTATE_0 | REFLECT_X)
Blob drm_property_create_blob() 임의 바이너리 데이터 MODE_ID (drm_mode_modeinfo), EDID
Object drm_property_create_object() 다른 KMS 오브젝트 ID CRTC_ID, FB_ID, IN_FENCE_FD
Signed Range drm_property_create_signed_range() 부호 있는 정수 SRC_X, SRC_Y (16.16 고정소수점)

표준 KMS Property

/* === CRTC Properties === */
"ACTIVE"           /* bool: CRTC 활성화 (atomic에서 DPMS 대체) */
"MODE_ID"          /* blob: 디스플레이 모드 (해상도/주사율) */
"OUT_FENCE_PTR"    /* ptr: 커밋 완료 fence fd 반환 위치 */
"VRR_ENABLED"      /* bool: 가변 주사율 활성화 */
"DEGAMMA_LUT"      /* blob: 디감마 LUT (Color Management) */
"CTM"              /* blob: 색 변환 매트릭스 (3x3, S31.32 고정소수) */
"GAMMA_LUT"        /* blob: 감마 LUT */

/* === Plane Properties === */
"FB_ID"            /* object: 표시할 프레임버퍼 */
"CRTC_ID"         /* object: 연결할 CRTC */
"SRC_X/Y/W/H"     /* range: 소스 영역 (16.16 고정소수점) */
"CRTC_X/Y/W/H"    /* range: 화면 위 위치/크기 (스케일링) */
"rotation"         /* bitmask: ROTATE_0/90/180/270 | REFLECT_X/Y */
"alpha"            /* range: 투명도 (0=투명, 0xFFFF=불투명) */
"pixel blend mode" /* enum: None/Pre-multiplied/Coverage */
"zpos"             /* range: 레이어 순서 (높을수록 위) */
"IN_FENCE_FD"      /* range: explicit sync 입력 fence fd */
"COLOR_ENCODING"   /* enum: YCbCr BT.601/709/2020 */
"COLOR_RANGE"      /* enum: YCbCr Limited/Full Range */

/* === Connector Properties === */
"CRTC_ID"          /* object: 연결할 CRTC */
"DPMS"             /* enum: On/Standby/Suspend/Off (레거시) */
"link-status"      /* enum: Good/Bad — 링크 학습 실패 시 Bad */
"EDID"             /* blob: 모니터 EDID 바이너리 (읽기 전용) */
"content type"     /* enum: No Data/Graphics/Photo/Cinema/Game */
"max bpc"          /* range: 최대 색 깊이 (bits per component) */
"HDR_OUTPUT_METADATA" /* blob: HDR 정적/동적 메타데이터 */
"vrr_capable"      /* range: 모니터 VRR 지원 여부 (읽기 전용) */
/* 드라이버에서 커스텀 property 등록 */
struct drm_property *prop;

/* Enum property 생성 */
static const struct drm_prop_enum_list my_scaling_modes[] = {
    { 0, "None" },
    { 1, "Full" },
    { 2, "Center" },
    { 3, "Full aspect" },
};
prop = drm_property_create_enum(dev, 0, "scaling mode",
        my_scaling_modes, ARRAY_SIZE(my_scaling_modes));

/* CRTC에 property 연결 */
drm_object_attach_property(&crtc->base, prop, 0);

/* atomic_check에서 property 값 읽기 */
static int my_crtc_atomic_check(struct drm_crtc *crtc,
                                struct drm_atomic_state *state)
{
    struct drm_crtc_state *crtc_state =
        drm_atomic_get_new_crtc_state(state, crtc);
    /* crtc_state에서 property 값에 접근 */
    ...
}
Property 조회 도구: modetest -M <driver> -p로 모든 KMS 오브젝트의 property와 현재 값을 확인할 수 있습니다. 유저 공간에서는 DRM_IOCTL_MODE_GETPROPERTY로 property 메타데이터를, DRM_IOCTL_MODE_OBJ_GETPROPERTIES로 오브젝트별 값을 조회합니다.

Color Management 파이프라인

KMS는 CRTC 레벨에서 3단계 색상 처리 파이프라인을 제공합니다. 이 파이프라인으로 HDR 톤매핑, 색 공간 변환, 감마 보정 등을 하드웨어 가속으로 수행합니다.

Plane 합성된 픽셀 1. Degamma LUT DEGAMMA_LUT 비선형 → 선형 변환 (sRGB/PQ EOTF 역변환) 2. CTM Color Transform 3×3 매트릭스 곱셈 (색 공간 변환) 3. Gamma LUT GAMMA_LUT 선형 → 비선형 변환 (디스플레이 감마 적용) 출력 Encoder LUT 크기: DEGAMMA_LUT_SIZE, GAMMA_LUT_SIZE property로 하드웨어 지원 엔트리 수 확인 (읽기 전용). 일반적으로 256 또는 4096 엔트리. CTM은 항상 3×3 = 9개 S31.32 고정소수점 값 (struct drm_color_ctm).
/* Color Management 관련 구조체 */

/* 감마/디감마 LUT 엔트리 (유저 공간에서 설정) */
struct drm_color_lut {
    __u16 red;      /* 0~0xFFFF */
    __u16 green;
    __u16 blue;
    __u16 reserved;
};

/* 색 변환 매트릭스 (CTM) — S31.32 고정소수점 */
struct drm_color_ctm {
    __u64 matrix[9];   /* 3x3, 부호 비트 + 31.32 고정소수 */
};

/* 유저 공간에서 감마 LUT 설정 예시 (libdrm) */
struct drm_color_lut lut[256];
for (int i = 0; i < 256; i++) {
    /* sRGB 감마 커브: 선형 → sRGB 비선형 */
    double v = (double)i / 255.0;
    double srgb = (v <= 0.0031308) ?
        v * 12.92 : 1.055 * pow(v, 1.0/2.4) - 0.055;
    __u16 val = (__u16)(srgb * 0xFFFF);
    lut[i].red = lut[i].green = lut[i].blue = val;
}
/* blob property로 설정 */
drmModeCreatePropertyBlob(fd, lut, sizeof(lut), &blob_id);
/* atomic 커밋에 GAMMA_LUT=blob_id 추가 */
HDR 지원: HDR10에서는 HDR_OUTPUT_METADATA connector property로 SMPTE ST 2086 마스터링 디스플레이 정보와 MaxCLL/MaxFALL 값을 설정합니다. PQ(Perceptual Quantizer) EOTF는 Degamma LUT로 처리하며, BT.2020 색 공간 변환은 CTM으로 수행합니다. 하드웨어가 충분한 LUT 정밀도(최소 1024 엔트리)를 제공해야 정확한 HDR 재현이 가능합니다.

VRR (Variable Refresh Rate) / Adaptive Sync

VRR은 GPU 렌더링 속도에 맞춰 디스플레이 주사율을 동적으로 조절하는 기술입니다. 화면 찢어짐(tearing)과 스터터링(stuttering) 없이 부드러운 프레임 전달을 가능하게 합니다.

기술표준DRM 지원설명
Adaptive-Sync VESA DP Adaptive-Sync DisplayPort connector DP 표준의 VRR. FreeSync 모니터가 주로 사용
HDMI VRR HDMI 2.1 VRR HDMI connector HDMI Forum VRR. QFT (Quick Frame Transport) 포함
Panel Self Refresh eDP PSR/PSR2 eDP connector 정적 화면에서 패널이 자체 리프레시 → GPU 절전
/* VRR 활성화 흐름 (커널 내부) */

/* 1. Connector가 VRR 지원하는지 확인 */
/*    모니터 EDID의 Adaptive-Sync range 파싱 */
connector->vrr_capable = true;  /* 드라이버가 EDID 기반으로 설정 */

/* 2. 유저 공간에서 CRTC의 VRR_ENABLED property 설정 */
/*    → atomic commit에 포함 */
new_crtc_state->vrr_enabled = true;

/* 3. 드라이버 atomic_check에서 VRR 설정 검증 */
static int my_crtc_atomic_check(struct drm_crtc *crtc,
                                struct drm_atomic_state *state)
{
    struct drm_crtc_state *crtc_state =
        drm_atomic_get_new_crtc_state(state, crtc);

    if (crtc_state->vrr_enabled) {
        /* VRR 범위 확인 (min_vfreq ~ max_vfreq) */
        struct drm_connector *conn = get_connector(crtc_state);
        if (!conn->display_info.monitor_range.max_vfreq)
            return -EINVAL;

        /* 하드웨어 VRR 타이밍 설정 */
        my_state->vmin = conn->display_info.monitor_range.min_vfreq;
        my_state->vmax = conn->display_info.monitor_range.max_vfreq;
    }
    return 0;
}

/* 4. 페이지 플립 시 VRR 타이밍 적용 */
/*    GPU가 프레임을 완료하면 즉시 vsync 발생 */
/*    → 가변 vblank 주기 */
Fixed Refresh vs VRR (Variable Refresh Rate) 타이밍 비교 Fixed (60Hz) VB VB VB VB VB VB VB 빈 공간 = 프레임 대기 (스터터링) | 빨간 바 = 프레임 초과 (티어링/드롭) VRR (48~144Hz) VB VB VB VB VB VB VB 짧음 길음 짧음 Vblank 간격이 프레임 렌더링 시간에 맞춰 동적으로 조절 → 스터터링/티어링 없음 프레임 렌더링 시간 VB = Vblank (Fixed: 고정 간격) VB = Vblank (VRR: 가변 간격)
VRR 확인 명령:
  • modetest -M amdgpu -p에서 vrr_capable property 확인
  • cat /sys/class/drm/card0-DP-1/vrr_capable — sysfs에서 직접 조회
  • Wayland에서는 wp_tearing_control_v1 프로토콜로 VRR/tearing 제어
  • X11에서는 xrandr --prop으로 VRR 속성 확인

Format Modifier (타일링/압축)

GPU는 메모리 접근 효율을 위해 픽셀 데이터를 단순 행(linear) 방식이 아닌 타일(tile) 형태로 배치합니다. Format Modifier는 프레임버퍼의 메모리 레이아웃을 기술하는 64비트 토큰입니다.

/* Format Modifier 구조 (include/uapi/drm/drm_fourcc.h) */
/*
 * [63:56] = vendor (DRM_FORMAT_MOD_VENDOR_*)
 * [55:0]  = vendor별 modifier 값
 *
 * 0 = DRM_FORMAT_MOD_LINEAR (행 순차 배치, 모든 디바이스 공통)
 */

#define DRM_FORMAT_MOD_LINEAR  0

/* Intel 타일링 modifier 예시 */
#define I915_FORMAT_MOD_X_TILED    /* X-tiling (레거시) */
#define I915_FORMAT_MOD_Y_TILED    /* Y-tiling (Gen9+) */
#define I915_FORMAT_MOD_4_TILED    /* Tile-4 (Gen12.5+, DG2/MTL) */
#define I915_FORMAT_MOD_Y_TILED_CCS /* Y-tiling + CCS 압축 */

/* AMD modifier 예시 */
#define AMD_FMT_MOD                /* 타일 버전, pipe_xor_bits, DCC 등 인코딩 */

/* ARM AFBC (Arm Frame Buffer Compression) */
#define DRM_FORMAT_MOD_ARM_AFBC    /* Mali GPU 프레임버퍼 무손실 압축 */

/* Broadcom */
#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED /* VideoCore T-tiling */

/* NVIDIA */
#define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D /* GOB 기반 타일링 */
Format Modifier: 메모리 레이아웃 비교 Linear (행 순차) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 메모리 순서 메모리: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 행별 연속 Tiled (4x2 타일) Tile A 0 1 2 3 8 9 10 11 Tile B 4 5 6 7 12 13 14 15 메모리: 0 1 2 3 8 9 10 11 4 5 6 7 12 13 14 15 타일별 연속 Compressed (타일+압축) Tile A (CCS/DCC) 압축 데이터 0~3, 8~11 Tile B (CCS/DCC) 압축 데이터 4~7, 12~15 Meta 압축 맵 메모리: A(압축) B(압축) Meta 대역폭 30~50% 절감 압축+메타 메모리 대역폭 사용량 비교 Linear 100% Tiled ~85% Compressed ~50~70%
레이아웃설명장점단점
Linear 행 순차 배치 (pitch × height) 모든 디바이스 호환, 단순 GPU 캐시(Cache) 효율 낮음
Tiled 정사각 또는 직사각 타일 단위 배치 2D 공간 지역성 향상, GPU 캐시 효율 디바이스별 포맷 비호환
Compressed 타일링 + 무손실 압축 (CCS, DCC, AFBC) 메모리 대역폭 절감 30~50% 디바이스 간 공유 시 압축 해제 필요
/* 프레임버퍼 생성 시 modifier 지정 (ADDFB2) */
struct drm_mode_fb_cmd2 cmd = {
    .width   = 1920,
    .height  = 1080,
    .pixel_format = DRM_FORMAT_XRGB8888,
    .handles[0] = gem_handle,
    .pitches[0] = pitch,
    .modifier[0] = I915_FORMAT_MOD_Y_TILED, /* modifier 지정 */
    .flags   = DRM_MODE_FB_MODIFIERS,       /* modifier 사용 플래그 */
};
drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &cmd);

/* Plane이 지원하는 modifier 목록 조회 */
/* DRM_IOCTL_MODE_GETPLANE2 또는 IN_FORMATS blob property */
/* → (format, modifier) 쌍의 목록 반환 */

/* 드라이버: Plane에 지원 modifier 등록 */
static const uint64_t my_modifiers[] = {
    DRM_FORMAT_MOD_LINEAR,
    I915_FORMAT_MOD_Y_TILED,
    I915_FORMAT_MOD_Y_TILED_CCS,
    DRM_FORMAT_MOD_INVALID  /* 종료 마커 */
};
drm_universal_plane_init(dev, plane, ...,
    formats, num_formats, my_modifiers, ...);
Modifier 호환성: DMA-BUF로 버퍼를 공유할 때 modifier가 다르면 importer가 버퍼를 읽을 수 없습니다. 디바이스 간 버퍼 공유 시에는 DRM_FORMAT_MOD_LINEAR를 사용하거나, 양쪽 디바이스가 모두 지원하는 modifier를 협상해야 합니다. Wayland에서는 zwp_linux_dmabuf_v1 프로토콜로 compositor와 클라이언트 간 modifier를 협상합니다.

DRM 드라이버 기본 구조

최소한의 KMS DRM 드라이버 (디스플레이만 지원, GPU 가속 없음)의 골격입니다.

#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_fbdev_shmem.h>

struct my_drm {
    struct drm_device              drm;
    struct drm_simple_display_pipe pipe;
    struct drm_connector           connector;
    void __iomem                  *regs;
};

/* --- Connector --- */
static int my_connector_get_modes(struct drm_connector *conn)
{
    /* 고정 해상도 모드 추가 (실제로는 EDID 파싱) */
    return drm_add_modes_noedid(conn, 1920, 1080);
}

static const struct drm_connector_helper_funcs my_conn_helpers = {
    .get_modes = my_connector_get_modes,
};

/* --- Simple Display Pipe --- */
static void my_pipe_enable(struct drm_simple_display_pipe *pipe,
                           struct drm_crtc_state *crtc_state,
                           struct drm_plane_state *plane_state)
{
    struct my_drm *my = container_of(pipe, struct my_drm, pipe);
    struct drm_framebuffer *fb = plane_state->fb;

    /* 하드웨어 레지스터에 프레임버퍼 주소/포맷 설정 */
    writel(drm_fb_dma_get_gem_addr(fb, plane_state, 0),
           my->regs + FB_ADDR_REG);
    writel(fb->pitches[0], my->regs + FB_PITCH_REG);
    /* 디스플레이 엔진 활성화 */
    writel(1, my->regs + DISPLAY_ENABLE_REG);
}

static void my_pipe_update(struct drm_simple_display_pipe *pipe,
                           struct drm_plane_state *old_state)
{
    struct drm_plane_state *state = pipe->plane.state;
    if (state->fb)
        my_pipe_enable(pipe, NULL, state);
}

static const struct drm_simple_display_pipe_funcs my_pipe_funcs = {
    .enable  = my_pipe_enable,
    .update  = my_pipe_update,
};

/* --- DRM Driver --- */
DEFINE_DRM_GEM_FOPS(my_fops);

static const struct drm_driver my_driver = {
    .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
    .fops            = &my_fops,
    DRM_GEM_SHMEM_DRIVER_OPS,
    .name  = "my-display",
    .desc  = "My simple display driver",
    .date  = "20260101",
    .major = 1,
    .minor = 0,
};

/* --- Platform Driver --- */
static int my_probe(struct platform_device *pdev)
{
    struct my_drm *my;
    struct drm_device *drm;
    static const uint32_t formats[] = { DRM_FORMAT_XRGB8888 };
    int ret;

    my = devm_drm_dev_alloc(&pdev->dev, &my_driver,
                            struct my_drm, drm);
    if (IS_ERR(my))
        return PTR_ERR(my);
    drm = &my->drm;

    /* MMIO 매핑 */
    my->regs = devm_platform_ioremap_resource(pdev, 0);
    if (IS_ERR(my->regs))
        return PTR_ERR(my->regs);

    /* Connector 초기화 */
    drm_connector_init(drm, &my->connector,
                       &my_conn_funcs, DRM_MODE_CONNECTOR_Unknown);
    drm_connector_helper_add(&my->connector, &my_conn_helpers);

    /* Simple display pipe 초기화 (CRTC+Plane+Encoder 한 번에) */
    ret = drm_simple_display_pipe_init(drm, &my->pipe,
            &my_pipe_funcs, formats, ARRAY_SIZE(formats),
            NULL, &my->connector);
    if (ret)
        return ret;

    drm_mode_config_reset(drm);
    ret = drm_dev_register(drm, 0);
    if (ret)
        return ret;

    /* fbdev 에뮬레이션 (콘솔 출력) */
    drm_fbdev_shmem_setup(drm, 32);
    return 0;
}

MODULE_LICENSE("GPL");
drm_simple_display_pipe: 간단한 디스플레이 전용 드라이버(CRTC 1개, Plane 1개, Encoder 1개)에 적합한 헬퍼입니다. 복잡한 다중 CRTC/Plane 구성이 필요하면 각 KMS 오브젝트를 개별적으로 초기화해야 합니다.

주요 오픈소스 DRM 드라이버

드라이버하드웨어커널 경로메모리 관리특징
i915 Intel 내장 GPU drivers/gpu/drm/i915/ GEM + GTT/GGTT GuC/HuC 펌웨어(Firmware) 지원, Display 13/14, Xe 드라이버로 전환 중
xe Intel Xe GPU (DG2+) drivers/gpu/drm/xe/ TTM 기반 i915 후속. 디스크리트 GPU(Arc) 지원, drm_sched 사용
amdgpu AMD Radeon (GCN+) drivers/gpu/drm/amd/ TTM DC (Display Core), KFD (HSA 컴퓨트), SR-IOV, RAS
nouveau NVIDIA (리버스 엔지니어링) drivers/gpu/drm/nouveau/ TTM 커뮤니티 개발, 최신 GPU 지원 제한적, GSP 펌웨어 지원
panfrost ARM Mali (Midgard/Bifrost) drivers/gpu/drm/panfrost/ GEM shmem OpenGL ES 지원, drm_sched 사용, MMU 자체 관리
lima ARM Mali (Utgard) drivers/gpu/drm/lima/ GEM shmem 레거시 ARM Mali-400/450, OpenGL ES 2.0
vc4 Broadcom VideoCore IV drivers/gpu/drm/vc4/ GEM CMA Raspberry Pi 0~3. v3d는 Pi 4/5용 별도 드라이버
msm Qualcomm Adreno drivers/gpu/drm/msm/ GEM Freedreno 스택, submitqueue 기반 커맨드 제출
virtio-gpu 가상 GPU (QEMU/virgl) drivers/gpu/drm/virtio/ GEM shmem VM 내 3D 가속, virglrenderer로 호스트 GPU 사용
simpledrm EFI/BIOS 프레임버퍼 drivers/gpu/drm/tiny/simpledrm.c GEM shmem 부팅 초기 콘솔. UEFI GOP/VBE 프레임버퍼 위에서 동작
nouveau 참고: NVIDIA는 공식 오픈소스 커널 드라이버를 별도로 제공합니다 (Turing 이후, nvidia-open). nouveau는 커뮤니티 리버스 엔지니어링 기반으로, 최신 GPU에서는 전력 관리(reclocking)와 성능이 제한됩니다. 최근 커널에서는 GSP(GPU System Processor) 펌웨어를 통해 nouveau의 기능이 개선되고 있습니다.

최근 DRM 코어의 방향

버전 번호 자체보다 중요한 것은 메인라인이 어떤 설계 축으로 이동하는가입니다. 최근 DRM 문서와 헤더를 보면 다음 네 가지 흐름이 거의 모든 드라이버 설계에 공통으로 반영됩니다.

최근 방향실무 의미
권한 분리 primary/render/accel 노드 역할이 더 명확해짐 display server, 일반 앱, AI runtime이 같은 fd 모델을 공유하지 않도록 설계해야 합니다.
상태 객체 확장 atomic property가 색 관리, writeback, HDR/VRR, content protection까지 포괄 새 기능은 대개 ioctl 추가보다 property/state 추가로 들어옵니다.
동기화 명시화 dma_resv, syncobj, explicit sync, timeline fence 사용이 확대 render 완료와 KMS 표시 완료를 같은 fence 체인으로 연결하는 능력이 중요해집니다.
복구/관측성 drm_sched timeout, reset recovery, drm_panic, tracepoint 강화 좋은 드라이버는 빠르기만 한 것이 아니라 hang 후에도 원인과 복구 경로를 설명할 수 있어야 합니다.
drm_panic의 위치: GPU가 패닉 화면을 직접 그리는 기능은 “최근 흐름”의 일부입니다. 하지만 이것은 특정 드라이버가 패닉 시점에도 안전하게 최소 렌더 경로를 유지할 수 있어야 가능한 기능이므로, 일반적인 fast path 설계와는 분리해서 생각해야 합니다.

DRM Bridge & Panel 프레임워크

임베디드/모바일 SoC에서는 디스플레이 출력이 여러 개의 하드웨어 블록 체인으로 구성됩니다. drm_bridge는 이 체인의 중간 단계(MIPI-DSI to HDMI 변환기, LVDS 직렬화(Serialization)기 등)를, drm_panel은 최종 디스플레이 패널을 추상화합니다.

Encoder SoC 디스플레이 출력 Bridge #1 예: DSI→HDMI (lt9611, sii902x 등) Bridge #2 예: LVDS 직렬화기 (sn65dsi86 등) Panel drm_panel (또는 Connector) LCD 각 Bridge는 pre_enable → enable → disable → post_disable 콜백을 체인 순서로 실행 DRM 코어가 체인 순회를 자동 관리 (atomic helper)
/* DRM Bridge 드라이버 구현 예시 */
#include <drm/drm_bridge.h>

static const struct drm_bridge_funcs my_bridge_funcs = {
    /* 디스플레이 파이프라인 활성화 순서 */
    .pre_enable  = my_bridge_pre_enable,  /* PLL/클럭 설정 */
    .enable      = my_bridge_enable,      /* 출력 활성화 */
    .disable     = my_bridge_disable,
    .post_disable = my_bridge_post_disable,

    /* 모드 검증 */
    .mode_valid  = my_bridge_mode_valid,  /* 지원 해상도 필터링 */
    .mode_fixup  = my_bridge_mode_fixup,  /* adjusted_mode 수정 */

    /* Atomic 지원 (권장) */
    .atomic_pre_enable = my_bridge_atomic_pre_enable,
    .atomic_enable     = my_bridge_atomic_enable,
    .atomic_disable    = my_bridge_atomic_disable,

    /* 출력 감지 (DRM_BRIDGE_OP_DETECT) */
    .detect      = my_bridge_detect,
    .get_modes   = my_bridge_get_modes,   /* EDID 기반 모드 목록 */
    .get_edid    = my_bridge_get_edid,    /* EDID 읽기 */
};

static int my_bridge_probe(struct i2c_client *client)
{
    struct my_bridge *mb = devm_kzalloc(&client->dev, sizeof(*mb), GFP_KERNEL);

    mb->bridge.funcs = &my_bridge_funcs;
    mb->bridge.of_node = client->dev.of_node;
    mb->bridge.type = DRM_MODE_CONNECTOR_HDMIA;  /* 출력 커넥터 타입 */
    mb->bridge.ops = DRM_BRIDGE_OP_DETECT |
                     DRM_BRIDGE_OP_EDID |
                     DRM_BRIDGE_OP_MODES;

    drm_bridge_add(&mb->bridge);
    return 0;
}
/* DRM Panel 드라이버 구현 예시 */
#include <drm/drm_panel.h>

static const struct drm_panel_funcs my_panel_funcs = {
    .prepare    = my_panel_prepare,     /* 전원 ON, 리셋 해제 */
    .enable     = my_panel_enable,      /* 백라이트 ON, 디스플레이 ON */
    .disable    = my_panel_disable,     /* 백라이트 OFF */
    .unprepare  = my_panel_unprepare,   /* 전원 OFF */
    .get_modes  = my_panel_get_modes,   /* 고정 모드 반환 */
};

static int my_panel_probe(struct mipi_dsi_device *dsi)
{
    struct my_panel *panel = devm_kzalloc(&dsi->dev, sizeof(*panel), GFP_KERNEL);

    drm_panel_init(&panel->panel, &dsi->dev, &my_panel_funcs,
                   DRM_MODE_CONNECTOR_DSI);
    drm_panel_add(&panel->panel);
    return 0;
}

/* 디스플레이 드라이버에서 bridge + panel 연결 */
struct drm_bridge *bridge;
bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
/* drm_panel은 자동으로 panel-bridge로 래핑됨 */
drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);

/* 체인의 마지막 bridge에서 connector 생성 */
connector = drm_bridge_connector_init(drm, encoder);
Device Tree 바인딩: Bridge와 Panel은 Device Tree의 ports/port/endpoint 노드로 연결됩니다. of_graph_get_remote_port_parent()로 연결된 디바이스를 탐색하고, devm_drm_of_get_bridge()가 DT 그래프를 따라 bridge 또는 panel-bridge를 자동으로 찾습니다.

DRM ioctl 요약

ioctl용도필요 권한
DRM_IOCTL_VERSION드라이버 이름/버전 조회없음
DRM_IOCTL_GET_CAP기능 조회 (PRIME, ATOMIC 등)없음
DRM_IOCTL_MODE_GETRESOURCESCRTC/Connector/Encoder ID 목록없음
DRM_IOCTL_MODE_GETCONNECTORConnector 상태, 지원 모드 조회없음
DRM_IOCTL_MODE_GETENCODEREncoder 정보 조회없음
DRM_IOCTL_MODE_GETCRTCCRTC 현재 모드 조회없음
DRM_IOCTL_MODE_SETCRTC모드 설정 (레거시)DRM Master
DRM_IOCTL_MODE_ATOMICAtomic 모드 설정/페이지 플립DRM Master
DRM_IOCTL_MODE_CREATE_DUMBDumb 버퍼 생성없음
DRM_IOCTL_MODE_MAP_DUMBDumb 버퍼 mmap 오프셋없음
DRM_IOCTL_MODE_DESTROY_DUMBDumb 버퍼 해제없음
DRM_IOCTL_PRIME_HANDLE_TO_FDGEM → DMA-BUF fd없음
DRM_IOCTL_PRIME_FD_TO_HANDLEDMA-BUF fd → GEM없음
DRM_IOCTL_GEM_CLOSEGEM 핸들 해제없음
DRM_IOCTL_MODE_ADDFB2프레임버퍼 객체 생성없음
DRM_IOCTL_MODE_PAGE_FLIP페이지 플립 (레거시)DRM Master
DRM_IOCTL_SET_CLIENT_CAP클라이언트 기능 활성화 (ATOMIC 등)DRM Master

DRM Lease (디스플레이 리스)

DRM Lease는 DRM Master가 자신의 KMS 리소스(CRTC, Connector, Plane) 일부를 다른 프로세스에게 독점적으로 위임하는 메커니즘입니다. VR 헤드셋, 멀티시트 디스플레이, 게임 전용 출력 등에서 사용됩니다.

DRM Master (Wayland Compositor) CRTC 0,1 / Conn 0,1 Plane 0,1,2,3 Lease #1 Lease #2 Lessee #1 (VR) CRTC 1 + Conn 1 (HMD) 독립적인 DRM Master 권한 Lessee #2 CRTC 0 + Conn 0 별도 디스플레이 관리 VR 헤드셋 메인 모니터
ioctl설명호출자
DRM_IOCTL_MODE_CREATE_LEASE KMS 오브젝트 집합을 리스로 생성, lessee fd 반환 DRM Master (Lessor)
DRM_IOCTL_MODE_LIST_LESSEES 현재 활성 lessee 목록 조회 DRM Master
DRM_IOCTL_MODE_GET_LEASE 리스에 포함된 오브젝트 ID 목록 조회 Lessee
DRM_IOCTL_MODE_REVOKE_LEASE 리스 취소 (오브젝트 회수) DRM Master
/* DRM Lease 생성 (유저 공간, libdrm) */
uint32_t objects[] = {
    crtc_id,       /* 리스할 CRTC */
    connector_id,  /* 리스할 Connector */
    plane_id,      /* 리스할 Plane */
};

struct drm_mode_create_lease lease = {
    .object_ids   = (uint64_t)(uintptr_t)objects,
    .object_count = 3,
    .flags        = O_CLOEXEC | O_NONBLOCK,
};

drmIoctl(master_fd, DRM_IOCTL_MODE_CREATE_LEASE, &lease);
/* lease.lessee_id = 리스 ID */
/* lease.fd = lessee가 사용할 새 DRM fd */

/* Lessee는 lease.fd를 통해 리스된 오브젝트만 접근 가능 */
/* → 독립적인 atomic commit, 페이지 플립 수행 */
VR 활용: OpenXR 런타임(Monado 등)이 compositor로부터 VR 헤드셋 출력을 lease로 받아 직접 제어합니다. 이렇게 하면 compositor를 거치지 않고 HMD에 직접 프레임을 전달하여 latency를 최소화할 수 있습니다. Wayland에서는 wp_drm_lease_device_v1 프로토콜로 compositor가 lease를 제공합니다.

Content Protection (HDCP)

HDCP(High-bandwidth Digital Content Protection)는 디스플레이 출력의 콘텐츠를 암호화(Encryption)하여 무단 복제를 방지하는 DRM(Digital Rights Management) 기술입니다. Linux DRM 서브시스템은 KMS property를 통해 HDCP를 지원합니다.

HDCP 버전대역폭사용 인터페이스특징
HDCP 1.4 TMDS (HDMI 1.x/DP) HDMI, DP, DVI 기본 암호화, 리피터 인증
HDCP 2.2 HDMI 2.0+ HDMI 2.x 향상된 암호화(AES-128), LC 검증
HDCP 2.3 HDMI 2.1/DP 2.x HDMI 2.1, DP 2.x 최신 보안 개선
/* HDCP KMS Properties (Connector) */

/* "Content Protection" property */
/* 값: Undesired (0) → Desired (1) → Enabled (2) */
/*     유저가 Desired로 설정하면 드라이버가 HDCP 인증 시작 */
/*     성공 시 Enabled로 전환 (읽기 전용) */

/* "HDCP Content Type" property */
/* 값: Type 0 — HDCP 1.4+ 허용 */
/*     Type 1 — HDCP 2.2+ 필수 (4K UHD 콘텐츠) */

/* Connector에 HDCP property 등록 (드라이버) */
drm_connector_attach_content_protection_property(connector, true);
/* true = HDCP Content Type property도 함께 등록 */

/* HDCP 인증 흐름 (드라이버 내부) */
/* 1. 유저가 "Content Protection" = Desired 설정 */
/* 2. atomic_check에서 HDCP 요청 감지 */
/* 3. 드라이버가 수신기(모니터)와 HDCP 핸드셰이크 */
/*    - AKE_Init / AKE_Send_Cert / AKE_Send_Km ... */
/* 4. 인증 성공 → "Content Protection" = Enabled */
/* 5. 링크 실패/핫플러그 → "Content Protection" = Desired */
/*    → 유저 공간에 uevent 통보 → 재인증 시도 */
HDCP 인증 핸드셰이크 (HDCP 2.x) Transmitter (GPU) Receiver (모니터) 1. AKE_Init 2. AKE_Send_Cert 3. AKE_Send_Km 4. LC_Init 5. LC_Send_L' 6. SKE_Send_Eks 7. Encrypted Content (암호화된 콘텐츠 전송) 세션 시작 인증서 전송 마스터 키 로컬리티 검증 로컬리티 응답 세션 키 교환 AKE LC SKE AKE = Authentication and Key Exchange | LC = Locality Check | SKE = Session Key Exchange
HDCP 요구사항: HDCP는 하드웨어 지원이 필수입니다. GPU의 디스플레이 엔진이 HDCP 암호화를 지원해야 하며, 모니터/TV도 해당 HDCP 버전을 지원해야 합니다. Intel GPU(i915)와 AMD GPU(amdgpu DC)가 Linux에서 HDCP를 지원하는 주요 드라이버입니다. HDCP 키는 GPU 펌웨어 또는 NVRAM에 저장되며, 커널은 키 자체를 직접 관리하지 않습니다.

디스플레이 연결 프로토콜

프로토콜DRM Connector 타입최대 대역폭특징
HDMI 2.1 DRM_MODE_CONNECTOR_HDMIA/B 48 Gbps ARC/eARC, VRR, DSC, 4K@120Hz
DisplayPort 2.1 DRM_MODE_CONNECTOR_DisplayPort 80 Gbps (UHBR20) MST (데이지체인), DSC, Adaptive-Sync
eDP DRM_MODE_CONNECTOR_eDP DP 기반 내장 디스플레이 (노트북), PSR (Panel Self Refresh)
DSI (MIPI) DRM_MODE_CONNECTOR_DSI 레인당 ~4.5 Gbps 모바일/임베디드 디스플레이, 커맨드/비디오 모드
DPI (RGB) DRM_MODE_CONNECTOR_DPI 병렬 전송 패럴렐 RGB, 임베디드 LCD 직결
LVDS DRM_MODE_CONNECTOR_LVDS 채널당 ~112 MHz 레거시 노트북/산업용 패널
VGA DRM_MODE_CONNECTOR_VGA ~400 MHz (아날로그) 레거시 아날로그, DAC 필요
USB-C (DP Alt) DRM_MODE_CONNECTOR_USB DP 기반 USB Type-C를 통한 DP 출력, typec_mux 드라이버

DisplayPort MST (Multi-Stream Transport)

DP MST는 하나의 DP 출력에서 여러 디스플레이를 데이지 체인으로 연결하거나 MST 허브를 통해 분기하는 기술입니다. 커널은 drm_dp_mst_topology_mgr로 MST 토폴로지(Topology)를 관리합니다.

구성 요소커널 구조체역할
Topology Manager drm_dp_mst_topology_mgr MST 허브/브랜치 장치 탐색, 대역폭 할당, 핫플러그 처리
MST Port drm_dp_mst_port 브랜치 장치의 각 출력 포트 (downstream connector)
Payload drm_dp_mst_atomic_payload 각 스트림의 대역폭 할당 (시간 슬롯)
VCPI (Virtual Channel Payload ID) Atomic state 내장 가상 채널별 대역폭 크기 (시간 슬롯 수)
/* MST 토폴로지 매니저 초기화 (드라이버) */
drm_dp_mst_topology_mgr_init(&my->mst_mgr, &my->aux,
    16,   /* 최대 페이로드 수 */
    4,    /* 최대 레인 수 */
    conn_base_id);

/* MST 허브 감지 시 (HPD IRQ에서) */
drm_dp_mst_hpd_irq_handle_event(&my->mst_mgr, esi);
/* → 토폴로지 변경 시 connector 추가/제거 이벤트 */

/* MST 대역폭 계산 예시 */
/* DP 1.4 HBR3: 8.1 Gbps/레인 × 4 레인 = 32.4 Gbps 총 대역폭 */
/* 4K@60Hz (XRGB8888): ~12.5 Gbps 필요 → 63개 시간 슬롯 중 ~25개 사용 */
/* 나머지 슬롯으로 2번째 모니터 (FHD@60Hz) 연결 가능 */

DSC (Display Stream Compression)

DSC는 VESA가 표준화한 시각적 무손실(visually lossless) 디스플레이 압축입니다. 고해상도(8K, 4K@120Hz+)에서 DP/HDMI 대역폭 한계를 극복하기 위해 사용됩니다. Linux DRM에서는 drm_dsc_config로 DSC 파라미터를 관리합니다.

항목설명
압축률일반적으로 3:1 (24bpp → 8bpp), 최대 4:1 가능
슬라이스프레임을 수평 슬라이스로 분할하여 병렬 압축/복원. 슬라이스 수는 모니터 DSC 능력에 의존
커널 헬퍼drm_dsc_compute_rc_parameters()로 Rate Control 파라미터 자동 계산
협상Source(GPU)와 Sink(모니터) 양쪽이 DSC 지원해야 사용 가능. DPCD/EDID에서 DSC 능력 파싱
활용 예8K@60Hz (48 Gbps 필요 → HDMI 2.1 48 Gbps에 DSC 적용), DP MST에서 대역폭 절감
/* DSC 설정 예시 (드라이버 atomic_check에서) */
struct drm_dsc_config dsc_cfg = {};

dsc_cfg.line_buf_depth     = 13;
dsc_cfg.bits_per_component = 8;
dsc_cfg.bits_per_pixel     = 128;    /* 8 bpp × 16 (4비트 소수부) */
dsc_cfg.slice_width        = 1920;  /* 슬라이스 너비 */
dsc_cfg.slice_height       = 108;   /* 슬라이스 높이 */
dsc_cfg.pic_width          = 3840;
dsc_cfg.pic_height         = 2160;

/* RC (Rate Control) 파라미터 자동 계산 */
drm_dsc_compute_rc_parameters(&dsc_cfg);

/* PPS (Picture Parameter Set) 생성 → DP SDP 또는 HDMI infoframe으로 전송 */
drm_dsc_pps_payload_pack(pps_payload, &dsc_cfg);
Writeback Connector: DRM은 DRM_MODE_CONNECTOR_WRITEBACK 타입의 가상 커넥터를 지원합니다. 물리 디스플레이 대신 CRTC의 합성 결과를 GEM 버퍼에 기록합니다. 스크린 캡처, 녹화, 가상 디스플레이에 사용되며, drm_writeback_connector_init()으로 초기화합니다. Atomic commit에서 WRITEBACK_FB_IDWRITEBACK_OUT_FENCE_PTR property로 출력 버퍼와 완료 fence를 지정합니다.

fbdev 에뮬레이션

DRM/KMS는 /dev/fb0 (fbdev) 인터페이스를 에뮬레이션하여 레거시 애플리케이션(fbcon, Plymouth 등)과 콘솔 출력을 지원합니다. drm_fbdev_shmem, drm_fbdev_ttm, drm_fbdev_dma 등의 헬퍼가 GEM/TTM 버퍼를 fb_info에 연결하고, DRM atomic 경로로 브리지(Bridge)합니다.

참고: fbdev 서브시스템의 아키텍처, fb_info 구조체, fb_ops 콜백, DRM fbdev 헬퍼 상세, fbcon 연동 등의 상세 내용은 프레임버퍼 (fbdev) 전용 페이지를 참고하세요.

참고 사항

커널 소스 참고 경로:
  • drivers/gpu/drm/ — DRM 코어 + 모든 GPU 드라이버
  • include/drm/ — DRM 헤더 파일
  • include/uapi/drm/ — 유저 공간 API (ioctl, 구조체)
  • Documentation/gpu/ — 커널 공식 GPU 문서
우선적으로 볼 1차 문서:
  • DRM UAPI — primary/render node, client capability, dumb buffer 제약
  • DRM KMS — atomic modesetting, plane/connector/CRTC helper 계약
  • GPU Driver Documentation — 드라이버별 하위 문서 색인
  • DRM Panic — 패닉 화면 출력 설계와 제약
외부 참고 링크:
KMS 드라이버 개발 시 주의사항:
  • Atomic check 무결성(Integrity)atomic_check에서 부작용(side effect) 금지. 검증만 수행하고, 하드웨어 변경은 atomic_commit에서 수행
  • KMS 핫플러그 — Connector 상태 변경은 drm_kms_helper_hotplug_event()로 유저 공간에 통보. HPD(Hot Plug Detect) IRQ 핸들러에서 호출
  • 펌웨어 로딩 — 최신 GPU는 대부분 request_firmware()로 마이크로코드를 로딩합니다. initramfs에 펌웨어 포함 필요 (CONFIG_EXTRA_FIRMWARE)

이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.