Share via


아키텍처 및 구성 요소

참고

Windows 10 앱의 경우 DirectComposition 대신 Windows.UI.Composition API를 사용하는 것이 좋습니다. 자세한 내용은 시각적 계층을 사용하여 데스크톱 앱 현대화를 참조하세요.

이 항목에서는 Microsoft DirectComposition을 구성하는 구성 요소에 대해 설명합니다. 다음 섹션으로 구성됩니다.

소프트웨어 구성 요소

DirectComposition은 다음과 같은 기본 소프트웨어 구성 요소로 구성됩니다.

  • COM(구성 요소 개체 모델) 기반 공용 API를 구현하는 사용자 모드 애플리케이션 라이브러리(dcomp.dll)입니다.
  • DWM(데스크톱 창 관리자) 프로세스(dwm.exe)에서 호스트되고 실제 데스크톱 컴퍼지션을 수행하는 사용자 모드 컴퍼지션 엔진(dwmcore.dll)입니다.
  • 애플리케이션에서 컴퍼지션 엔진으로 명령을 마샬링하는 커널 모드 개체 데이터베이스(win32k.sys 일부)입니다.

컴퍼지션 엔진의 단일 instance 모든 애플리케이션에 대한 DirectComposition 컴퍼지션 트리와 전체 데스크톱을 나타내는 DWM 컴퍼지션 트리를 처리합니다. 커널 모드 개체 데이터베이스와 사용자 모드 컴퍼지션 엔진은 세션당 한 번씩 인스턴스화되므로 여러 사용자가 있는 터미널 서버 컴퓨터에는 두 구성 요소의 여러 인스턴스가 있습니다.

다음 다이어그램에서는 기본 DirectComposition 구성 요소와 이러한 구성 요소가 서로 어떻게 관련되는지 보여 줍니다.

직접 처리 최상위 아키텍처

애플리케이션 라이브러리

DirectComposition 애플리케이션 라이브러리는 dcomp.dll 내보내고 디바이스 개체에 대한 인터페이스 포인터를 반환하는 단일 플랫 진입점이 있는 공용 COM 기반 API입니다. 디바이스 개체에는 인터페이스 포인터로 표시되는 다른 모든 개체를 만드는 메서드가 있습니다. 모든 DirectComposition 인터페이스는 IUnknown 인터페이스에서 상속되고 완전히 구현됩니다. DirectComposition 인터페이스를 수락하는 모든 메서드는 인터페이스가 dcomp.dll 내에서 구현되는지 또는 다른 구성 요소에서 구현되는지 여부를 검사. DirectComposition은 확장할 수 없으므로 인터페이스를 매개 변수로 사용하는 메서드는 인터페이스가 dcomp.dll 구현되지 않은 경우 E_INVALIDARG 반환합니다. API에는 특별한 권한이 필요하지 않습니다. 가장 낮은 액세스 수준에서 실행되는 프로세스에서 호출할 수 있습니다. 그러나 API는 세션 0에서 작동하지 않으므로 서비스에 적합하지 않습니다. 이러한 측면에서 DirectComposition API는 다른 Microsoft DirectX API, 특히 Direct2D, Microsoft Direct3D 및 Microsoft DirectWrite 비슷합니다.

컴퍼지션 엔진은 비동기 실행을 위해 독점적으로 설계되었기 때문에 DirectComposition API의 개체 속성은 쓰기 전용입니다. 모든 속성에는 setter 메서드가 있지만 getter 메서드는 없습니다. 읽기 속성은 리소스 집약적일 뿐만 아니라 컴퍼지션 엔진이 반환하는 모든 값이 즉시 유효하지 않을 수 있으므로 부정확할 수도 있습니다. 예를 들어 독립 애니메이션이 읽는 속성에 바인딩된 경우에 발생할 수 있습니다.

API는 스레드로부터 안전합니다. 애플리케이션은 언제든지 스레드에서 모든 메서드를 호출할 수 있습니다. 그러나 많은 API 메서드가 특정 시퀀스에서 호출되어야 하므로 동기화 없이 애플리케이션은 스레드가 인터리브하는 방법에 따라 예측할 수 없는 동작을 경험할 수 있습니다. 예를 들어 두 스레드가 동일한 개체의 동일한 속성을 동시에 다른 값으로 변경하는 경우 애플리케이션은 두 값 중 속성의 최종 값이 될 값을 예측할 수 없습니다. 마찬가지로 두 스레드가 동일한 디바이스에서 커밋 을 호출하는 경우 한 스레드에서 커밋 을 호출하면 밋이라는 명령이 아니라 두 스레드에서 발급한 모든 명령의 일괄 처리를 제출하기 때문에 두 스레드 모두 진정한 트랜잭션 동작을 가져오지 않습니다.

시스템은 디바이스 개체당 모든 내부 상태를 유지 관리합니다. 애플리케이션에서 둘 이상의 DirectComposition 디바이스 개체를 만드는 경우 애플리케이션은 독립적인 일괄 처리 및 둘 사이의 다른 상태를 유지할 수 있습니다.

모든 DirectComposition 개체에는 디바이스 개체 선호도가 있습니다. 특정 디바이스 개체에서 만든 개체는 해당 디바이스 개체에서만 사용할 수 있으며 동일한 디바이스 개체에서 만든 다른 개체와만 연결할 수 있습니다. 즉, 각 디바이스 개체는 별도의 연결되지 않는 기능 아일랜드입니다. 한 가지 예외는 시각적 개체가 부모와 다른 디바이스 개체에 속할 수 있는 시각적 트리 빌드를 허용하는 시각적 개체 클래스입니다. 이렇게 하면 애플리케이션 및 컨트롤이 단일 DirectComposition 디바이스 개체를 공유할 필요 없이 단일 컴퍼지션 트리를 관리할 수 있는 시나리오가 가능합니다.

컴퍼지션 엔진

DirectComposition 컴퍼지션 엔진은 애플리케이션 프로세스와는 별도로 전용 프로세스에서 실행됩니다. dwm.exe 단일 컴퍼지션 프로세스는 세션의 모든 애플리케이션을 지원합니다. 각 애플리케이션은 소유하고 있는 각 창에 대해 두 개의 시각적 트리를 만들 수 있습니다. 모든 트리는 실제로 DWM의 컴퍼지션 구조를 포함하는 더 큰 시각적 트리의 하위 트리로 구현됩니다. DWM은 세션의 각 데스크톱에 대해 하나의 큰 시각적 트리를 생성합니다. 이 아키텍처의 주요 이점은 다음과 같습니다.

  • 컴퍼지션 엔진은 모든 애플리케이션 비트맵 및 시각적 트리에 액세스할 수 있으므로 프로세스 간 창 상호 운용성과 컴퍼지션을 사용할 수 있습니다.
  • 컴퍼지션 엔진은 애플리케이션 프로세스와 별개인 신뢰할 수 있는 시스템 프로세스에서 실행되므로 액세스 권한이 낮은 애플리케이션은 보호된 콘텐츠를 안전하게 작성할 수 있습니다.
  • 컴퍼지션 엔진은 특정 창이 완전히 폐색된 경우를 감지하고 창에 대한 CPU 및 GPU(그래픽 처리 장치) 리소스 낭비를 방지할 수 있습니다.
  • 컴퍼지션 엔진은 화면 뒤로 버퍼에 직접 구성하여 프로세스별 컴퍼지션 엔진에 필요한 추가 복사본이 필요하지 않도록 할 수 있습니다.
  • 모든 애플리케이션은 구성을 위해 단일 Direct3D 디바이스를 공유하므로 상당한 메모리 절감이 가능합니다.

시각적 트리는 유지된 구조체입니다. DirectComposition API는 원자성으로 처리되는 변경 내용의 일괄 처리로 구조를 편집하는 메서드를 노출합니다. DirectComposition API의 루트 개체는 다른 모든 DirectComposition 개체의 팩터리 역할을 하며 Commit이라는 메서드를 포함하는 디바이스 개체입니다. 컴퍼지션 엔진은 애플리케이션이 Commit을 호출할 때까지 애플리케이션이 시각적 트리에 적용하는 변경 내용을 반영하지 않으며, 이때 마지막 커밋 이후의 모든 변경 내용이 단일 트랜잭션으로 처리됩니다.

커밋을 호출해야 하는 요구 사항은 컴퍼지션 엔진이 비동기적으로 실행되기 때문에 Commit 호출 간에 여러 프레임을 표시할 수 있다는 점을 제외하고는 "프레임"의 개념과 비슷합니다. DirectComposition에서 프레임 은 컴퍼지션 엔진의 단일 반복이며 커 에 대한 두 호출 간의 애플리케이션에서 사용하는 간격을 일괄 처리라고 합니다.

DirectComposition은 DirectComposition API에 대한 모든 애플리케이션 호출을 일괄 처리합니다. win32k.sys 세션 드라이버에서 구현되는 커널 개체 데이터베이스는 API 호출과 연결된 모든 상태 정보를 저장합니다.

컴퍼지션 엔진은 디스플레이의 각 세로 공백에 대해 하나의 프레임을 생성합니다. 프레임은 세로 공백에서 시작되며 후속 세로 공백을 대상으로 합니다. 프레임이 시작되면 컴퍼지션 엔진은 보류 중인 모든 일괄 처리를 선택하고 해당 프레임에 해당 명령을 포함합니다. 애플리케이션이 Commit을 호출하면 일괄 처리가 보류 중인 큐에 배치되고, 보류 중인 큐는 프레임의 시작 부분에서 원자성으로 플러시됩니다. 따라서 프레임의 시작을 표시하는 단일 시점이 있습니다. 이 지점 이전에 제출된 모든 일괄 처리는 프레임에 포함되며, 이후에 제출된 모든 일괄 처리는 다음 프레임이 처리될 때까지 기다려야 합니다. 전체 컴퍼지션 루프는 다음과 같습니다.

  1. 다음 세로 공백의 시간을 예측합니다.
  2. 보류 중인 모든 일괄 처리를 검색합니다.
  3. 검색된 일괄 처리를 처리합니다.
  4. 1단계에서 예상한 시간을 사용하여 모든 애니메이션을 업데이트합니다.
  5. 다시 작성해야 하는 화면의 영역을 결정합니다.
  6. 더티 지역을 다시 작성합니다.
  7. 각 화면의 후면 및 전면 버퍼를 대칭 이동하여 프레임을 표시합니다.
  8. 6단계와 7단계에서 아무것도 구성되고 표시되지 않으면 일괄 처리가 커밋될 때까지 기다립니다.
  9. 다음 세로 공백을 기다립니다.

단일 비디오 어댑터에 연결된 모니터가 여러 대 있는 경우 컴퍼지션 엔진은 기본 모니터의 세로 공백을 사용하여 컴퍼지션 루프를 구동하고 애니메이션 샘플링 시간을 설정합니다. 각 모니터는 별도의 전체 화면 대칭 이동 체인으로 표시됩니다. 컴퍼지션 엔진은 단일 Direct3D 디바이스를 사용하여 라운드 로빈 방식으로 각 모니터에 대해 6단계와 7단계를 반복합니다. 비디오 어댑터가 여러 개 있는 경우 컴퍼지션 엔진은 6단계와 7단계에서 각 비디오 어댑터에 대해 별도의 Direct3D 디바이스를 사용합니다.

컴퍼지션 프레임은 다음 그림과 같이 항상 세로 공백에서 시작하도록 예약됩니다.

컴퍼지션 프레임 예약

컴퍼지션 트리가 변경되지 않았기 때문에 컴퍼지션 엔진에서 수행할 작업이 없는 경우 새 일괄 처리를 기다리는 동안 컴퍼지션 스레드가 절전 모드로 전환됩니다. 새 일괄 처리가 제출되면 컴퍼지션 스레드가 절전 모드에서 해제되지만 즉시 다음 세로 공백까지 절전 모드로 돌아갑니다. 이 동작은 애플리케이션 및 컴퍼지션 엔진에 대한 예측 가능한 프레임 시작 및 종료 시간을 보장합니다.

컴퍼지션 엔진은 프레임 프레젠테이션 시간과 현재 프레임 속도를 게시합니다. 이 정보를 게시하면 애플리케이션에서 자체 일괄 처리에 대한 프레젠테이션 시간을 예측할 수 있으므로 애니메이션을 동기화할 수 있습니다. 특히 애플리케이션은 컴퍼지션 엔진의 프레임 통계 조합과 UI 스레드가 일괄 처리를 생성하는 데 걸리는 시간의 기록 모델을 사용하여 자체 애니메이션의 샘플링 시간을 결정할 수 있습니다.

예를 들어 이전 그림에 표시된 애플리케이션 일괄 처리의 시작 부분에서 애플리케이션은 컴퍼지션 엔진을 쿼리하여 다음 프레임의 정확한 프레젠테이션 시간을 확인할 수 있습니다. 그런 다음 애플리케이션은 생성한 이전 일괄 처리에 대한 정보와 함께 현재 시간을 사용하여 애플리케이션이 다음 세로 공백 전에 현재 일괄 처리를 완료할 수 있는지 여부를 결정할 수 있습니다. 따라서 애플리케이션은 프레임 프레젠테이션 시간을 자체 애니메이션의 샘플링 시간으로 사용합니다. 애플리케이션이 현재 세로 공백에서 작업을 완료할 가능성이 낮다고 판단하는 경우 애플리케이션은 컴퍼지션 엔진에서 반환된 프레임 속도 정보를 사용하여 후속 프레임 시간을 샘플링 시간으로 대신 사용하여 해당 시간을 계산할 수 있습니다.

DirectComposition 개념