언리얼 렌더링 시스템 분석(16) - 그래픽 드라이버의 비밀
🌐 원문 링크: 剖析虚幻渲染体系(16)- 图形驱动的秘密 (cnblogs.com/timlly)
📅 원문 발행일: 2022-06-25 | ✍️ 저자: Timlly (00 / )💡 시리즈 분류:
Unreal Engine Rendering| 국내 업계 표준 용어 감수 및 수식/도해 복원 적용 완료
지금까지 블로그에서 블로거가 설명한 내용에는 그래픽 API, GPU, 게임 엔진, 셰이더, 렌더링 기술, 성능 최적화 및 기타 기술적 측면이 포함되어 있지만 그래픽 드라이버의 내부 이야기는 다루지 않은 것 같습니다. 이 기사에서는 애플리케이션 계층 개발자의 관점에서 그래픽 드라이버에 대한 기술적 내부 지식을 설명합니다(드라이버 개발자인 경우 블로거는 대상 독자로 간주되지 않습니다). 여기에는 주로 다음 내용이 포함되지만 이에 국한되지는 않습니다.
그래픽 기반 아키텍처.
그래픽 기반 기술에 대한 내막.
그래픽 드라이버의 일반적인 구현.
관련 하드웨어 기반.
16.1.2 장치 드라이버 개요
'드라이브'라는 단어를 정확하게 정의하는 것은 어려운 일입니다. 가장 기본적인 의미에서 드라이버는 운영 체제와 장치가 서로 통신할 수 있도록 하는 소프트웨어 구성 요소입니다. 예를 들어, 애플리케이션이 장치에서 일부 데이터를 읽어야 하고, 애플리케이션이 운영 체제에 의해 구현된 함수를 호출하고, 운영 체제가 드라이버에 의해 구현된 함수를 호출한다고 가정해 보겠습니다. 드라이버는 장치를 설계하고 제작한 회사에서 작성했으며, 이 회사는 장치 하드웨어와 통신하여 데이터를 얻는 방법을 알고 있습니다. 드라이버는 장치에서 데이터를 얻은 후 해당 데이터를 운영 체제에 반환하고, 운영 체제는 해당 데이터를 응용 프로그램에 반환합니다.

컴퓨터에서 장치 드라이버는 컴퓨터나 자동 장치에 연결된 특정 유형의 장치를 작동하거나 제어하는 데 사용되는 컴퓨터 프로그램입니다. 드라이버는 하드웨어 장치에 소프트웨어 인터페이스를 제공하여 운영 체제 및 기타 컴퓨터 프로그램이 사용 중인 하드웨어의 정확한 세부 정보를 알지 못해도 하드웨어 기능에 액세스할 수 있도록 합니다.
드라이버는 하드웨어가 연결된 컴퓨터 버스나 통신 하위 시스템을 통해 장치와 통신합니다. 호출 프로그램이 드라이버의 루틴을 호출하면 드라이버는 장치에 명령을 내립니다(장치를 구동합니다). 장치가 데이터를 다시 드라이버로 전송하면 드라이버는 원래 호출 프로그램에서 루틴을 호출할 수 있습니다. 드라이버는 하드웨어에 따라 다르며 운영 체제에 따라 다르며 일반적으로 비동기 시간 관련 하드웨어 인터페이스에 필요한 인터럽트 처리를 제공합니다.
특히 최신 Microsoft Windows 플랫폼의 장치 드라이버는 커널 모드(x86 CPU의 링 0) 또는 사용자 모드(x86 CPU의 링 3)에서 실행될 수 있습니다. 사용자 모드에서 드라이버를 실행하는 주요 이점은 안정성이 향상된다는 것입니다. 잘못 작성된 사용자 모드 장치 드라이버는 커널 메모리를 덮어써도 시스템이 충돌할 수 없기 때문입니다. 반면에 사용자/커널 모드 전환은 상당한 성능 오버헤드를 발생시키는 경우가 많으므로 지연 시간이 짧은 네트워크에서는 커널 모드 드라이버가 선호됩니다.
사용자 모듈은 시스템 호출을 통해서만 커널 공간에 액세스할 수 있습니다. 최종 사용자 프로그램(예: UNIX 셸 또는 기타 GUI 기반 응용 프로그램)은 사용자 공간의 일부이며 이러한 응용 프로그램은 커널 지원 기능을 통해 하드웨어와 상호 작용합니다.
일반적인 장치 드라이버에는 다음이 포함되지만 이에 국한되지는 않습니다.
프린터.
비디오 어댑터.
네트워크 카드.
사운드 카드.
특히 현대 시스템에서 버스를 제어하기 위한 다양한 유형의 지역 버스.
다양한 저대역폭 입출력 버스(마우스, 키보드 등 포인팅 장치용).
하드 드라이브, CD-ROM 및 플로피 디스크 버스(ATA, SATA, SCSI, SAS)와 같은 컴퓨터 저장 장치.
다양한 파일 시스템에 대한 지원을 구현합니다.
이미지 스캐너.
디지털 카메라.
디지털 지상파 TV 튜너.
홈 자동화(예: BLE(Bluetooth Low Energy), Thread, ZigBee 및 Z-Wave)에서 단거리, 저속 무선 통신을 위한 무선 개인 영역 네트워크용 RF 통신 트랜시버 어댑터입니다.
IrDA 어댑터.
위의 설명은 다음 측면에서 너무 단순합니다.
모든 드라이버를 장치를 설계한 회사에서 작성할 필요는 없습니다. 대부분의 경우 장치는 게시된 하드웨어 표준에 따라 설계됩니다. 즉, 드라이버는 Microsoft에서 작성할 수 있으며 장치 설계자는 드라이버를 제공할 필요가 없습니다.
모든 드라이버가 장치와 직접 통신하는 것은 아닙니다. 특정 I/O 요청(예: 장치에서 데이터 읽기)의 경우 일반적으로 요청에 참여하는 여러 드라이버가 있으며 이러한 드라이버는 드라이버 스택에 계층화됩니다. 스택을 시각화하는 전통적인 방법은 아래 이미지에 표시된 것처럼 첫 번째 액터가 맨 위에 있고 마지막 액터가 맨 아래에 있는 것입니다. 스택의 일부 드라이버는 요청을 한 형식에서 다른 형식으로 변환하는 것과 관련될 수 있습니다. 이러한 드라이버는 장치와 직접 통신하지 않으며 단지 요청을 조작하여 스택의 하위 드라이버에 전달합니다.

기능 드라이버는 스택 내에서 장치와 직접 통신하는 드라이버이고, 필터 드라이버는 보조 처리를 수행하는 드라이버이다.
- 일부 필터 드라이버는 입력/출력 요청에 대한 정보를 관찰하고 기록하지만 이러한 요청에 적극적으로 참여하지는 않습니다. 예를 들어, 일부 필터 드라이버는 스택의 다른 드라이버가 I/O 요청을 올바르게 처리하는지 확인하는 유효성 검사기 역할을 합니다.
드라이버는 운영 체제와 장치 간의 통신을 관찰하거나 이에 참여하는 모든 소프트웨어 구성 요소라고 말함으로써 드라이버의 정의를 확장할 수 있습니다.
이 시점에서 확장 정의는 상당히 정확하지만 일부 드라이버가 하드웨어 장치와 전혀 연결되어 있지 않기 때문에 여전히 불완전합니다. 예를 들어, 커널 모드에서 실행되는 코드를 통해서만 액세스할 수 있는 핵심 운영 체제 데이터 구조에 액세스할 수 있는 도구를 작성해야 한다고 가정해 보겠습니다. 이는 도구를 두 개의 구성 요소로 분할하여 달성할 수 있습니다. 첫 번째 구성 요소는 사용자 모드에서 실행되어 사용자 인터페이스를 표시하고, 두 번째 구성 요소는 커널 모드에서 실행되며 핵심 운영 체제 데이터에 액세스합니다. 사용자 모드에서 실행되는 구성 요소를 응용 프로그램이라고 하며, 커널 모드에서 실행되는 구성 요소를 소프트웨어 드라이버라고 합니다. 소프트웨어 드라이버는 하드웨어 장치와 연결되지 않습니다. 다음 다이어그램은 커널 모드 소프트웨어 드라이버와 통신하는 사용자 모드 애플리케이션을 보여줍니다.

소프트웨어 드라이버는 항상 커널 모드에서 실행되며 소프트웨어 드라이버를 작성하는 주된 이유는 커널 모드에서만 사용할 수 있는 보호된 데이터에 액세스하기 위한 것입니다. 그러나 장치 드라이버가 항상 커널 모드 데이터 및 리소스에 액세스할 필요는 없습니다. 따라서 일부 장치 드라이버는 사용자 모드에서 실행됩니다.
또한 버스 드라이버와 기타 보다 기능적인 드라이버도 있습니다(아래 그림).

16.1.3 그래픽 드라이버 개요
디스플레이 드라이버는 운영 체제가 그래픽 하드웨어와 함께 작동할 수 있도록 해주는 소프트웨어입니다. 그래픽 하드웨어는 디스플레이를 제어합니다. 디스플레이는 컴퓨터의 확장 카드일 수도 있고 컴퓨터의 주 회로 기판(예: 노트북)에 내장되거나 컴퓨터 외부(예: Matrox 원격 그래픽 장치)에 있을 수도 있습니다. 각 모델의 그래픽 하드웨어는 다르며 시스템의 나머지 부분과 인터페이스하려면 디스플레이 드라이버가 필요합니다. 최신 그래픽 하드웨어 모델은 다양한 기능을 갖춘 지속적으로 출시되고 있으며 각각의 새 모델은 다르게 제어되는 경우가 많습니다.
드라이버는 운영 체제 기능 호출(명령)을 해당 장치에 특정한 호출로 변환합니다. 서로 다른 함수 호출을 사용하는 각 운영 체제에는 동일한 그래픽 하드웨어 모델에 대해 서로 다른 디스플레이 드라이버도 필요합니다. 예를 들어, Windows XP와 Linux에는 매우 다른 디스플레이 드라이버가 필요합니다. 그러나 동일한 운영 체제의 서로 다른 버전이 동일한 디스플레이 드라이버를 사용할 수 있는 경우가 있습니다. 예를 들어, Windows 2000과 Windows XP용 디스플레이 드라이버는 일반적으로 동일합니다.
컴퓨터의 그래픽 하드웨어와 관련된 디스플레이 드라이버가 설치되어 있지 않으면 그래픽 하드웨어를 사용할 수 없거나 기능이 제한됩니다. 모델별 디스플레이 드라이버를 사용할 수 없는 경우 운영 체제는 일반적으로 기본 기능을 갖춘 일반 디스플레이 드라이버를 사용할 수 있습니다. 예를 들어 Windows는 "안전 모드"에서 일반 VGA 또는 SVGA 디스플레이 드라이버를 사용합니다. 이 경우 대부분의 모델별 기능을 사용할 수 없습니다.
그래픽 하드웨어는 매우 복잡하고 디스플레이 드라이버는 해당 하드웨어에만 적용되므로 디스플레이 드라이버는 하드웨어 제조업체에서 만들고 유지 관리하는 경우가 많으며 운영 체제에 포함된 디스플레이 드라이버도 원래 제조업체에서 제공하는 경우가 많습니다. 제조업체는 하드웨어에 대한 모든 정보에 접근할 수 있으며 하드웨어가 가능한 최상의 방법으로 사용되도록 보장하는 데 큰 관심을 가지고 있습니다.
디스플레이 드라이버에는 시스템 리소스에 대한 낮은 수준(커널 수준) 액세스 권한이 있습니다. 디스플레이 드라이버는 그래픽 하드웨어와 직접 통신해야 하기 때문에 이러한 낮은 수준의 액세스를 통해 디스플레이 드라이버를 보다 신중하고 안정적으로 코딩할 수 있습니다. 디스플레이 드라이버의 버그는 응용 프로그램 소프트웨어의 버그보다 전체 운영 체제를 일시적으로 사용할 수 없게 만들 가능성이 더 높습니다.
다행스럽게도 Matrox와 같은 특정 회사나 조직은 전문 사용자에 대한 전통적인 노력과 제품의 긴 제품 수명 주기 덕분에 안정적인 모니터 드라이버를 만드는 것으로 확고한 평판을 얻고 있습니다. 수명 주기가 길다는 것은 디스플레이 드라이버의 개발이 더 오랜 기간 동안 계속된다는 것을 의미하므로 미해결 문제가 해결되고 디스플레이 드라이버가 변화하는 소프트웨어 환경에 적응할 수 있을 가능성이 높아집니다. 새로운 운영 체제와 새로운 응용 프로그램 소프트웨어는 지속적으로 출시되고 있으며 각각 호환성을 유지하거나 새로운 기능을 제공하기 위해 새로운 드라이버 버전이 필요할 수 있으며 사용 가능한 최신 디스플레이 드라이버는 이러한 문제를 해결하는 경우가 많습니다. 제품 수명 주기가 길어지면 디스플레이 드라이버가 운영 체제 및 응용 프로그램 소프트웨어에 관계없이 새로운 특징과 기능을 추가할 가능성도 높아집니다.
Linux와 같은 오픈 소스 운영 체제에서는 디스플레이 드라이버가 제조업체가 아닌 곳에서 유지 관리되는 경우가 있으며, 운영 체제의 오픈 소스 특성으로 인해 이러한 운영 체제용 코드를 작성하는 것이 더 쉬워집니다(그러나 쉽지는 않습니다). Matrox는 특별한 목적을 위해 자체 Linux 디스플레이 드라이버를 유지 관리하지만 Matrox Millennium G-Series 제품에는 기본 오픈 소스 Linux 디스플레이 드라이버가 제공되며 Matrox 파트너 Xi Graphics(Linux/Unix 개발 분야에서 10년 이상의 경험을 보유한 회사)는 Matrox 제품을 위한 모든 기능을 갖춘 Linux 디스플레이 드라이버를 제공합니다.
운영 체제와 그래픽 하드웨어 모델이 동일하더라도 다양한 요구 사항을 충족하기 위해 다양한 디스플레이 드라이버를 동시에 사용할 수 있는 경우가 있습니다. 다음은 Matrox 그래픽 하드웨어의 특정 모델에 사용할 수 있는 다양한 디스플레이 드라이버에 대한 요약입니다.
"HF" 드라이버: 이 유형의 드라이버는 풍부한 인터페이스를 갖추고 있으며 이 인터페이스를 선호하거나 이미 갖고 있는 사용자를 위해 Microsoft .NET Framework 소프트웨어가 필요합니다. Microsoft .NET 소프트웨어는 최신 Windows 설치 및 이를 필요로 하는 기타 여러 응용 프로그램에 포함되어 있습니다. "HF" 소프트웨어는 Parhelia 시리즈 및 Millennium P 시리즈 제품의 특정 모델에서만 사용할 수 있습니다.
Microsoft .NET Framework: HF 드라이버와 같은 .NET 기술을 사용하여 애플리케이션과 서비스를 구축, 배포 및 실행하기 위해 Microsoft에서 만든 프로그래밍 인프라입니다.
통합 드라이버: 이 드라이버는 Matrox 제품의 여러 모델을 동시에 지원합니다. 다양한 Matrox 제품용 디스플레이 드라이버를 한 번에 설치해야 하고 단일 패키지로 설치하려는 시스템 관리자와 그래픽 하드웨어 모델을 잘 모르는 사용자에게 유용합니다. 통합 드라이버의 인터페이스는 다양한 하드웨어를 지원해야 하기 때문에 Matrox 통합 드라이버는 더 넓은 범위의 하드웨어를 지원하는 "SE" 인터페이스를 사용합니다.
XDDM: Windows XP 디스플레이 드라이버 모델(때때로 XPDM 또는 XPDDM이라고도 함)
WDDM: WDDM(Windows 디스플레이 드라이버 모델)은 Windows Vista, Server 2008 및 Windows 7에서 지원되는 디스플레이 드라이버 아키텍처입니다.
"WDM"(Windows 드라이버 모델) 드라이버 패키지: 이 유형의 드라이버는 Microsoft의 .NET Framework 소프트웨어 및 비디오 지원이 필요한 풍부한 인터페이스의 추가 기능과 함께 비디오 캡처 및 실시간 재생 기능이 필요한 사용자를 위한 것입니다. 최근 설치된 Windows 및 이를 필요로 하는 많은 기타 응용 프로그램에 포함된 Microsoft .NET 소프트웨어입니다. Parhelia 제품군의 특정 모델에서만 사용할 수 있습니다.
WHQL 드라이버: "Windows Hardware Quality Labs" 드라이버는 드라이버 신뢰성을 향상시키기 위해 Microsoft에서 개발한 일련의 표준 테스트를 거칩니다. Matrox와 같은 하드웨어 공급업체는 이러한 테스트를 수행하고 인증을 위해 결과를 Microsoft에 제출합니다. 최신 버전의 Windows 운영 체제에서는 WHQL 인증을 받지 않은 드라이버를 설치하는 경우(드라이버가 달리 인증된 경우에도) 사용자에게 경고합니다. 이러한 경고와 WHQL 프로세스에서 제공되는 추가 테스트를 피하기 위해 시스템 관리자는 WHQL 드라이버 사용을 선호하는 경우가 많습니다.
인증 드라이버: Matrox는 종종 그래픽 하드웨어 가속을 요구하고 광범위하게 사용하는 AEC, MCAD, GIS 및 P&P(플랜트 및 공정 설계)용 소프트웨어를 포함하여 선도적인 전문 2D/3D 소프트웨어로 디스플레이 드라이버를 인증합니다. Matrox는 추가적인 신뢰성을 보장하기 위해 이러한 애플리케이션을 개별적으로 인증합니다. 이 테스트는 모든 Matrox 모니터 드라이버에 대해 수행되는 정기 테스트에 추가되는 것입니다.
ISV 인증 드라이버: 특정 "독립 소프트웨어 공급업체"는 특정 그래픽 하드웨어용 디스플레이 드라이버가 특정 응용 프로그램에서 추가 테스트를 거친다는 점에서 Matrox 인증 드라이버와 유사하게 응용 프로그램 소프트웨어에 대한 자체 인증 프로세스를 갖추고 있습니다. 그러나 이 경우 Matrox는 하드웨어 및 디스플레이 드라이버를 ISV에 제출하여 테스트를 수행합니다. Matrox 인증에 비해 ISV 인증은 빈도가 낮고 적용되는 응용 프로그램이 더 적습니다.
베타 드라이버: 때때로 특별 지원이나 수정 사항이 "베타" 드라이버로 먼저 릴리스됩니다. 이러한 드라이버는 일부 테스트를 거쳤지만 전체 테스트 주기를 반드시 완료하지는 않았습니다. 중요한 새 기능을 테스트하거나 미리 보려는 사용자는 베타 드라이버를 사용할 수 있습니다.
-......
장치 드라이버는 Linux 커널에 500만 줄 이상의 코드가 포함되어 운영 체제 커널 코드에 가장 큰 기여를 하며 상당한 복잡성, 버그 및 개발 비용을 유발할 수 있습니다. 최근에는 신뢰성을 높이고 드라이버 개발을 단순화하기 위한 일련의 연구가 진행되었습니다. 그러나 연구에 사용되는 일부 드라이버 하위 집합을 제외하고는 이 대규모 코드 본문의 구성에 대해 알려진 바가 거의 없습니다.
학자들은 Linux 드라이버의 소스 코드를 연구하여 실제로 어떤 드라이버가 사용되는지, 현재 연구가 이러한 드라이버에 어떻게 적용되는지, 향후 연구 기회를 이해합니다. 일반적으로 연구에서는 드라이버 코드의 세 가지 측면을 살펴봅니다.
드라이버 코드 기능의 특징은 무엇이며 드라이버 연구가 모든 드라이버에 어떻게 적용되는지.
드라이버가 커널, 장치 및 버스와 상호 작용하는 방법.
드라이버 크기와 복잡성을 줄이기 위해 라이브러리로 추상화할 수 있는 유사점이 있습니까?
드라이버 상호 작용 연구를 통해 USB 버스는 격리된 드라이버 실행에 이상적인 중요한 표준화된 코드와 대략적인 액세스를 갖춘 효율적인 버스 인터페이스를 제공하는 것으로 나타났습니다. 또한 장치 상호 작용 수준은 버스와 드라이버 수준에 따라 크게 다르므로 격리 비용은 수준에 따라 달라질 수 있습니다.
장치 드라이버는 운영 체제와 하드웨어 장치 간의 인터페이스를 제공하는 소프트웨어 구성 요소입니다. 드라이버는 장치를 구성 및 관리하고 커널의 요청을 하드웨어에 대한 요청으로 변환합니다. 드라이버는 세 가지 인터페이스를 사용합니다.
요청을 전달하고 운영 체제 서비스에 액세스하기 위한 드라이버와 커널 간의 인터페이스입니다.
작업을 수행하는 데 사용되는 드라이브와 장치 간의 인터페이스입니다.
드라이버와 장치와의 통신을 관리하는 버스 사이의 인터페이스입니다.
아래 그림은 인터페이스에 따른 Linux 드라이버의 계층 구조를 보여줍니다. 기본 드라이버 유형, 즉 char, block 및 net부터 시작하여 72개의 고유한 드라이버 범주를 식별할 수 있습니다. 드라이버 코드의 대부분(52%)은 41개 클래스에 걸쳐 있는 문자 드라이버입니다. 네트워크 드라이버는 드라이버 코드의 25%를 차지하지만 클래스는 6개뿐입니다. 예를 들어 비디오 및 GPU 드라이버는 복잡한 장치에 각 세대에 따라 변경되는 명령어 세트가 있기 때문에 드라이버 코드에 크게 기여하지만(거의 9%) 이러한 장치는 복잡성으로 인해 드라이버 연구에서 크게 무시되었습니다.

기본 드라이버 클래스에 따른 Linux 드라이버 분류. 여기에는 가장 큰 5개 클래스의 크기(코드 줄의 백분율로 표시)가 언급되어 있습니다.
장치 드라이버를 주로 입력/출력을 수행하는 것으로 생각하는 것이 일반적입니다. 표준 학부 운영 체제 교과서에는 다음과 같이 명시되어 있습니다. 장치 드라이버는 입력이 "검색 블록 123"과 같은 상위 수준 명령으로 구성되고 출력이 입/출력 장치를 시스템의 나머지 부분에 연결하는 하드웨어 컨트롤러에서 사용하는 하위 수준 하드웨어 관련 명령으로 구성되는 변환기로 생각할 수 있습니다.
장치가 더욱 강력해지고 자체 프로세서를 갖게 되면서 드라이버는 운영 체제와 장치 간에 데이터를 전송하는 것 외에는 거의 처리를 수행하지 않는 것으로 간주되는 경우가 많습니다. 그러나 드라이버에 RAID 패리티 계산, 네트워크 체크섬 또는 데이터 표시 비디오 드라이버와 같은 상당한 CPU 처리가 필요한 경우 처리 능력을 보존해야 합니다. 15%의 드라이버에는 처리를 수행하는 기능이 하나 이상 있으며 전체 드라이버 기능 중 1%에서 처리가 발생합니다.
아래 표에서는 PCI, USB 및 XenBus에 대한 모든 장치 범주의 복잡성 메트릭을 비교합니다. 드라이버가 지원하는 칩셋 수를 비교하여 여러 장치 지원의 효율성을 살펴보면 새로운 장치 지원의 복잡성과 드라이버의 추상화 수준을 알 수 있습니다. 다양한 공급업체의 많은 칩셋을 지원하는 드라이버는 높은 수준의 공통 기능을 갖춘 표준화된 인터페이스를 나타냅니다. 반면, 단일 칩셋에 대한 드라이버 지원은 각 장치에 별도의 드라이버가 필요하므로 효율성이 떨어집니다.

세 가지 유형의 버스의 운전 효율성은 크게 다릅니다. PCI 드라이버는 거의 항상 동일한 공급업체의 드라이버당 7.5개의 칩셋을 지원합니다. 이에 비해 일반적으로 많은 공급업체에서 제공하는 USB 드라이버의 평균 드라이버는 13.2입니다. 차이점의 큰 부분은 많은 PCI 장치에 존재하지 않는 USB 프로토콜의 표준화에 있습니다. 예를 들어 USB 저장 장치는 표준 인터페이스를 구현합니다. 따라서 기본 USB 저장소 드라이버 코드는 대체로 일반적이지만 장치별 코드에 대한 호출을 포함합니다. 이 코드에는 장치별 초기화, 일시 중지/재개(USB 저장소를 통해 제공되지 않고 추가 기능 요구 사항으로 예약됨) 및 장치별 코드가 필요한 기타 루틴이 포함됩니다. USB 드라이버에 대한 표준화 작업이 활발히 이루어지고 있지만 아직 불완전합니다.
모든 최신 운영 체제의 드라이버에 대한 또 다른 주요 요구 사항은 다중 액세스 장치가 필요하다는 것입니다. 예를 들어, 디스크 컨트롤러 드라이버는 애플리케이션이 달리 관련되지 않은 경우에도 여러 애플리케이션이 동시에 데이터를 읽고 쓸 수 있도록 허용해야 합니다. 이 요구 사항은 여러 독립 스레드 간의 동기화 필요성을 증가시키므로 드라이버 설계를 복잡하게 만듭니다. 드라이버가 오랜 지연에 걸쳐 다중 액세스를 작동하는 방법을 조사하십시오. 코드를 스레드하고, 스택에 상태를 저장하고, 이벤트를 차단하는 경향이 있습니까? 아니면 이벤트 중심 코드를 사용하여 USB 드라이버의 완료 루틴으로 콜백을 등록하거나 PCI 장치의 핸들러 및 타이머를 인터럽트하는 경향이 있습니까? 드라이버가 커널 외부로 이동하면 드라이버와 커널은 통신 채널을 사용하여 서로 통신하므로 이벤트 기반 동시성을 지원하는 것이 더 자연스러울 수 있습니다.
아래 그림의 이벤트 친화적 코드와 스레드 코드가 표시된 막대 차트에 표시된 결과는 스레드 코드와 이벤트 친화적 코드의 구분이 드라이버 클래스에 따라 크게 다르다는 것을 보여줍니다. 전반적으로 드라이버는 서로 다른 목적으로 두 가지 동기화 방법을 광범위하게 사용합니다. 드라이버는 스레딩 프리미티브를 사용하여 드라이버와 장치 작업을 동기화하는 동시에 드라이버를 초기화하고 드라이버 전역 데이터 구조를 업데이트하며, 이벤트 친화적인 코드는 핵심 I/O 요청에 사용됩니다.

스레드 및 이벤트 친화적인 동기화 프리미티브가 포함하는 드라이버 진입점의 비율입니다.
GPU 성능이 향상됨에 따라 그래픽 드라이버에 대한 요구 사항도 점점 더 높아지고 있습니다. 좋은 사용자 경험은 안정적이고 신뢰할 수 있는 소프트웨어 스택에 달려 있습니다.
16.2 그래픽 드라이버 기본 사항
16.2.1 하드웨어 개요
대부분의 초기 컴퓨터 하드웨어 아키텍처(예: 2012)는 다음과 같은 형태로 추상화될 수 있습니다.

아래 그림에는 GPU(모든 계산 수행), 비디오 출력(화면에 연결됨), 비디오 메모리(텍스처 또는 일반 데이터 저장), 전원 관리(전압 감소, 전류 조절), 호스트 상호 작용 버스(CPU와의 통신)와 같은 구성 요소가 포함된 그래픽 카드 중 하나의 구조가 나와 있습니다.

오늘날 모든 컴퓨터는 중앙 처리 장치와 다양한 주변 장치 등 유사한 아키텍처를 가지고 있습니다. 데이터를 교환하기 위해 이러한 주변 장치는 모든 통신이 이루어지는 버스를 통해 상호 연결됩니다. 다음 다이어그램은 표준 컴퓨터의 주변 장치 레이아웃을 간략하게 보여줍니다.

일반적인 컴퓨터의 주변 장치 상호 연결.
버스의 첫 번째 사용자는 CPU입니다. CPU는 버스를 사용하여 시스템 메모리 및 기타 주변 장치에 액세스합니다. 그러나 CPU가 주변 장치에 데이터를 쓰고 읽을 수 있는 유일한 장치는 아닙니다. 주변 장치 자체에도 직접 정보를 교환할 수 있는 기능이 있습니다. 특히, CPU 개입 없이 메모리를 읽고 쓸 수 있는 주변 장치를 DMA(직접 메모리 액세스) 가능이라고 하며 메모리 트랜잭션을 종종 DMA라고 합니다. 이러한 유형의 트랜잭션은 드라이버가 메모리 전송을 위해 CPU 대신 GPU를 사용할 수 있다는 점에서 흥미롭습니다. CPU는 더 이상 이러한 전송을 구현하기 위해 적극적으로 작업할 필요가 없으며 CPU와 GPU 간의 더 나은 비동기성을 허용하므로 더 나은 성능을 달성할 수 있습니다. **DMA의 일반적인 용도에는 텍스처 업로드 또는 스트리밍 비디오의 성능 향상이 포함됩니다.**현재 모든 그래픽 프로세서에는 비디오 카드가 몇 마이크로초 동안 버스를 요청하고 제어하는 기능(DMA 버스 마스터링이라고 함)이 있습니다.
주변 장치가 연속되지 않은 메모리 페이지 목록에서 DMA를 구현할 수 있는 경우(데이터가 메모리에서 연속되지 않을 때 매우 편리함) DMA 분산 수집 기능이 있다고 합니다(데이터를 다른 메모리 페이지에 분산시키거나 다른 메모리 페이지에서 데이터를 수집할 수 있기 때문입니다).
**어떤 경우에는 DMA 기능이 단점이 될 수 있다는 점에 유의하세요.**예를 들어 실시간 시스템에서 이는 DMA 트랜잭션이 진행되는 동안 CPU가 버스에 액세스할 수 없으며 DMA 트랜잭션이 비동기적으로 발생하기 때문에 실시간 스케줄링 기한을 놓칠 수 있음을 의미합니다. 또 다른 예는 DMA 설정에 따른 CPU 오버헤드가 비동기 이득보다 커서 전송 속도가 느려지는 소규모 DMA 메모리 전송입니다. 따라서 DMA는 성능 측면에서 많은 장점이 있지만 특정 상황에서는 피해야 합니다.
또한 GPU에는 호스트가 필요합니다.
화면 모드/해상도를 설정합니다(모드 설정).
엔진 및 통신 버스를 구성합니다.
전원 관리를 처리합니다. 열 관리(팬, 과열/전력에 반응), GPU 주파수/전압을 변경하여 전력을 절약합니다.
프로세스 데이터. 처리 컨텍스트(GPU VM + 컨텍스트 ID)를 할당하고, 텍스처 또는 장면 데이터를 업로드하고, 컨텍스트에서 실행될 명령을 보냅니다.
16.2.2 버스 유형
버스는 기계 주변 장치를 함께 연결하며 서로 다른 주변 장치 간의 모든 통신은 (적어도) 하나의 버스를 통해 발생합니다. 특히, 버스는 대부분의 그래픽 카드가 컴퓨터의 나머지 부분에 연결되는 방식입니다(GPU가 CPU에 직접 연결되는 일부 임베디드 시스템은 예외입니다). 아래 표에 표시된 것처럼 PCI, AGP, PCI-X, PCI Express 등 그래픽에 적합한 버스 유형이 많이 있습니다. 이 섹션에서 자세히 설명할 모든 버스 유형은 PCI 버스 유형의 변형이지만 일부는 원래 PCI 설계에서 고유하게 개선되었습니다.

PCI(Peripheral Component Interconnect, Peripheral Component Interconnect Standard): PCI는 현재 그래픽 주변 장치의 연결을 허용하는 가장 기본적인 버스입니다. 주요 기능 중 하나는 버스 마스터링입니다. 이는 특정 주변 장치가 버스를 점유하고 지정된 사이클 수 동안 완전한 트랜잭션(DMA, 직접 메모리 액세스라고 함)을 수행할 수 있도록 하는 기능입니다. PCI 버스는 일관적입니다. 즉, 장치 전체에서 메모리의 일관성을 유지하기 위해 명시적인 플러시가 필요하지 않습니다.
AGP(가속 그래픽 포트, 가속 그래픽 포트): AGP는 본질적으로 이전 버전에 비해 많은 추가 기능을 갖춘 향상된 PCI 버스입니다. 게다가 더 높은 클럭 속도와 클럭 틱당 레인당 2, 4 또는 8비트를 전송할 수 있는 기능(AGP의 경우 각각 2x, 4x 및 8x) 덕분에 더 빠릅니다. AGP에는 세 가지 특징이 있습니다.
첫 번째 기능은 IOMMU의 간단한 형태인 AGP GART(Graphic Aperture Remapping Table)입니다. 이를 통해 시스템 메모리에서 일련의 (비연속) 물리적 메모리 페이지를 가져와 연속 영역으로 사용하기 위해 GPU에 노출할 수 있으며, 매우 저렴한 비용으로 GPU에서 사용할 수 있는 메모리 양을 늘리고, CPU와 GPU 간에 데이터를 공유하기 위한 편리한 영역을 생성할 수 있습니다. (AGP 그래픽 카드는 이 영역에서 빠른 DMA를 수행할 수 있으며, GART 영역은 시스템 RAM의 일부이므로 CPU 액세스가 VRAM보다 훨씬 빠릅니다.) 한 가지 중요한 단점은 GART 영역이 일관성이 없기 때문에 상대방이 전송을 시작하기 전에 GART에 대한 쓰기를 GPU 또는 CPU에서 플러시해야 한다는 것입니다. 또 다른 단점은 하드웨어가 드라이버에 의해 할당되어야 하는 하나의 GART 영역만 처리한다는 것입니다.
두 번째 기능은 SBA(AGP Sideband Addressing)입니다. 측대역 주소 지정은 주소 버스로 사용되는 8개의 추가 버스 비트로 구성됩니다. 주소와 데이터 간의 버스 대역폭을 다중화하는 것과 달리 표준 AGP 대역폭은 데이터에만 사용할 수 있습니다. 이 기능은 드라이버 개발자에게 투명합니다.
세 번째 기능은 AGP Fast Write(FW)입니다. Fast Write를 사용하면 그래픽 카드에서 DMA를 시작할 필요 없이 데이터를 그래픽 카드로 직접 보낼 수 있습니다. 이 기능은 드라이버 개발자에게도 투명합니다.
후자의 두 기능은 광범위한 하드웨어에서 불안정하며 제대로 작동하려면 칩셋별 해킹이 필요한 경우가 많으므로 활성화하지 않는 것이 좋습니다. 실제로 이는 AGP 카드에서 이상한 하드웨어 오류가 발생하는 매우 일반적인 원인입니다.
PCI-X: PCI-X는 서버 보드용으로 개발된 PCI의 더 빠른 버전이며 이 형식의 그래픽 주변 장치는 거의 없습니다(일부 Matrox G550 카드). 매우 널리 사용되는 PCI-Express와 혼동하지 마십시오.
PCI-Express(PCI-E): PCI Express는 단순히 PCI를 개선하는 것보다 더 많은 장점을 지닌 차세대 PCI 장비입니다. 마지막으로, 아키텍처에 따라 CPU-GPU 통신이 항상 버스에 의존하는 것은 아니라는 점에 유의하는 것이 중요합니다. 이는 GPU와 CPU가 단일 칩에 있는 임베디드 시스템에서 특히 일반적입니다. 이 경우 CPU는 GPU 레지스터에 직접 액세스할 수 있습니다.
16.2.3 비디오 메모리 아키텍처
DRAM은 일반적으로 플랫 바이트 어레이로 간주되지만 내부 구조는 훨씬 더 복잡합니다. GPU와 같은 고성능 애플리케이션의 경우 이를 깊이 있게 이해하는 것이 매우 필요합니다. 아래에서 위로 대략 살펴보면 VRAM은 다음과 같은 부분으로 구성됩니다.
- 행 R과 열 C의 메모리 평면, 셀당 1비트.

- 병렬로 사용되는 32개, 64개 또는 128개의 메모리 플레인으로 구성된 메모리 뱅크. 이러한 플레인은 일반적으로 여러 칩에 분산되어 있으며 하나의 칩에는 16개 또는 32개의 메모리 플레인이 포함되어 있습니다. 뱅크의 모든 페이지는 행 주소 지정 시스템(열도 마찬가지)에 연결되어 있으며 이러한 페이지는 각 행/열에 대한 명령 신호 및 주소에 의해 제어됩니다. 뱅크에 행과 열이 많을수록 주소에 더 많은 비트를 사용해야 합니다.

함께 연결되고 주소 비트에 의해 선택되는 여러 [2, 4 또는 8]개의 메모리 뱅크로 구성된 메모리 랭크 - 지정된 메모리 플레인의 모든 메모리 뱅크는 동일한 칩에 위치합니다.
함께 연결되고 칩 선택 라인에 의해 선택되는 하나 또는 두 개의 메모리 랭크로 구성된 메모리 하위 파티션입니다. 랭크는 뱅크처럼 동작하지만 균일한 기하학적 구조를 가질 필요는 없고 별도의 칩에 있습니다.
**메모리 파티션(메모리 파티션)**은 약간 독립적인 하나 또는 두 개의 메모리 하위 파티션으로 구성됩니다.
전체 VRAM은 여러 개의 [1-8] 메모리 파티션으로 구성됩니다.
위의 수치는 다양한 GPU 아키텍처 및 제품군에 따라 달라집니다.
DRAM의 가장 기본적인 단위는 소위 열과 행으로 구성된 2차원 비트 배열인 메모리 플레인입니다.
column
row 0 1 2 3 4 5 6 7
0 X X X X X X X X
1 X X X X X X X X
2 X X X X X X X X
3 X X X X X X X X
4 X X X X X X X X
5 X X X X X X X X
6 X X X X X X X X
7 X X X X X X X X
buf X X X X X X X X메모리 플레인에는 전체 행을 보유하는 버퍼가 포함되어 있습니다. 내부적으로 DRAM은 버퍼를 통해 행 단위로 읽고 쓰입니다. 이로 인해 다음과 같은 여러 가지 결과가 발생합니다.
비트 작업을 수행하기 전에 해당 행을 버퍼에 로드해야 하므로 속도가 느려질 수 있습니다.
행을 처리한 후 메모리 배열에 다시 기록해야 하는데 이 역시 속도가 느립니다.
따라서 새로운 행에 대한 접근이 느리며, 이미 활성화된 행이 있는 경우에는 접근이 더욱 느려집니다.
일정 기간 동안 활동이 없을 경우 은행을 선제적으로 폐쇄하는 것이 유용한 경우가 많습니다. 이 작업을 은행 선충전이라고 합니다.
그러나 동일한 행 내의 다른 열에 빠르게 액세스할 수 있습니다.
열 주소를 로드하는 것 자체는 활성 버퍼의 비트에 실제로 액세스하는 것보다 더 많은 시간이 걸리기 때문에 DRAM은 활성 행의 1~8개 인접 비트에 대한 일련의 액세스인 버스트 방식으로 액세스됩니다. 일반적으로 버스트의 모든 비트는 정렬된 단일 옥텟에 있어야 합니다. 메모리 플레인의 행과 열 수는 항상 2의 거듭제곱이며 행 선택 및 열 선택 비트 수로 측정됩니다. 행/열 개수의 log2], 일반적으로 8~10열 비트 및 10~14행 비트입니다. 메모리 평면은 두 개의 메모리 평면의 거듭제곱으로 구성된 뱅크로 구성됩니다. 메모리 평면은 병렬로 연결되어 주소와 제어 라인을 공유하며 데이터/데이터 활성화 라인만 분리됩니다. 이는 효과적으로 메모리 뱅크를 개별 비트가 아닌 32비트/64비트/128비트 메모리 셀로 구성된 메모리 플레인과 유사하게 만듭니다. 플레인에 적용되는 모든 규칙은 여전히 뱅크에 적용되지만 작동되는 셀은 비트보다 큽니다. 단일 메모리 칩에는 일반적으로 단일 뱅크에 대해 16개 또는 32개의 메모리 플레인이 포함되어 있으므로 여러 칩이 함께 연결되어 더 넓은 뱅크를 형성하는 경우가 많습니다.
메모리 칩에는 동일한 데이터 라인을 사용하고 뱅크 선택 라인에 의해 다중화되는 여러 [2, 4 또는 8] 뱅크가 포함되어 있습니다. 뱅크 간 전환은 행의 열 간 전환보다 느리지만, 동일한 뱅크의 행 간 전환보다는 훨씬 빠릅니다. 따라서 메모리 뱅크는 (MEMORY_CELL_SIZE / MEMORY_CELL_SIZE_PER_CHIP)개의 메모리 칩으로 구성됩니다. 칩 선택 라인을 제외하고 공통 라인(데이터 포함)으로 연결된 하나 또는 두 개의 메모리 열이 메모리 하위 파티션을 구성합니다. 순위 간 전환은 기본적으로 뱅크의 열 그룹 간 전환과 동일한 성능 결과를 가져옵니다. 유일한 차이점은 물리적 구현과 각 순위에 대해 다른 수의 행 선택 비트를 사용할 수 있다는 것입니다(열 수와 열 수는 일치해야 함). 여러 은행/순위의 결과:
함께 액세스되는 데이터가 동일한 행에 속하거나 다른 뱅크에 속하는지 확인하는 것이 중요합니다(행 전환을 방지하기 위해).
블록 메모리 레이아웃은 블록이 대략 행에 해당하고 인접한 블록이 뱅크를 공유하지 않도록 설계되었습니다.
메모리 하위 파티션에는 GPU에 자체 DRAM 컨트롤러가 있습니다. 1개 또는 2개의 하위 파티션이 메모리 파티션을 구성합니다. 이는 자체 메모리 액세스 큐, 자체 ZROP 및 CROP 장치, 이후 카드의 L2 캐시를 갖춘 상당히 독립적인 개체입니다. 모든 메모리 파티션은 크로스바 로직과 함께 GPU의 전체 VRAM 로직을 구성합니다. 파티션 내의 모든 하위 파티션은 동일하게 구성되어야 합니다. GPU의 파티션은 일반적으로 동일하게 구성되지만 최신 카드에서는 이것이 필요하지 않습니다. 하위 파티션/파티션 존재의 결과:
뱅크와 마찬가지로 관련 데이터에 대한 행 충돌을 피하기 위해 다른 파티션을 사용할 수 있습니다.
뱅크와 달리 (하위)파티션이 동일하게 활용되지 않으면 대역폭에 영향을 미칩니다. 따라서 로드 밸런싱이 매우 중요합니다.
메모리 주소 지정은 GPU 제품군에 크게 의존하지만 기본 접근 방식은 여기에 설명되어 있습니다. 메모리 주소의 비트는 다음에 순차적으로 할당됩니다.
어쨌든 전체 장치에 액세스해야 하므로 메모리 장치의 바이트를 식별합니다.
버스트를 허용하는 다중 열 선택 비트.
파티션/하위 파티션 선택 - 좋은 로드 밸런싱을 보장하려면 낮게 설정하세요. 그러나 ROP를 용이하게 하기 위해 상대적으로 큰 타일을 단일 파티션에 유지하기에는 너무 낮지 않게 설정하세요.
남은 열 선택 비트.
인접 주소가 행 충돌을 일으키지 않도록 모든/대부분의 뱅크 선택 비트 및 때로는 순위 선택 비트.
행 위치.
나머지 뱅크 비트 또는 순위 비트를 사용하면 VRAM을 두 영역으로 효과적으로 분할할 수 있습니다. 한 영역에는 컬러 버퍼가 배치되고 다른 영역에는 제타 버퍼가 배치되어 두 영역 사이에 행 충돌이 발생하지 않습니다.
또한 동적 랜덤 액세스 메모리는 DDR-SDRAM 또는 DDR로 알려진 데이터 속도의 다양한 배수로 동기화될 수 있습니다.

싱글 탱크와 더블 랭크의 비교입니다.

싱글레이트, 듀얼레이트, 쿼드레이트 비교표입니다.
다음 그림은 CPU 및 GPU 메모리 요청 경로를 보여줍니다.

GTT/GART는 통신을 위한 CPU-GPU 공유 버퍼로 사용됩니다.

16.2.4 가상 및 물리적 메모리
기억에는 두 가지 주요 의미가 있습니다.
물리적 기억. 물리적 메모리는 메모리 칩에 저장된 실제 하드웨어 메모리입니다.
가상 메모리. 가상 메모리는 사용자 공간 응용 프로그램이 할당된 블록을 연속된 것처럼 볼 수 있도록 하는 물리적 메모리 주소의 변환입니다. 반면 블록은 조각화되어 칩 전체에 분산되어 있습니다.

가상 주소 공간의 일부 주요 기능과 가상 메모리와 물리적 메모리의 관계.
일부 운영 체제(예: Windows)에는 페이징 풀 및 비페이징 풀에 대한 메커니즘도 있습니다. 사용자 공간에서 모든 물리적 메모리 페이지는 필요에 따라 디스크 파일로 페이지 아웃될 수 있습니다. 시스템 공간에서 일부 물리적 페이지는 페이지 아웃될 수 있지만 다른 페이지는 페이지 아웃될 수 없습니다. 시스템 공간에는 동적으로 할당된 메모리를 위한 두 가지 영역, 즉 페이징 풀과 비페이징 풀이 있습니다. 페이징 풀에 할당된 메모리는 필요에 따라 디스크 파일로 페이징될 수 있지만 비페이징 풀에 할당된 메모리는 디스크 파일로 페이징될 수 없습니다.

프로그래밍을 단순화하려면 인접한 메모리 영역을 처리하는 것이 더 쉽습니다. 작은 연속 영역을 할당하는 것은 쉽지만 더 큰 메모리 블록을 할당하려면 연속된 물리적 메모리가 그만큼 필요하므로 시작 후 메모리 조각화로 인해 달성하기가 어렵습니다. 따라서 분산된 메모리 블록을 사용하면서 애플리케이션에 대해 연속된 메모리 블록의 모양을 유지하는 메커니즘이 필요합니다.
이를 달성하기 위해 메모리는 페이지로 분할됩니다. 이 기사의 범위에서 메모리 페이지는 물리적 메모리에 있는 연속 바이트 모음이라고 말할 수 있습니다. 흩어져 있는 물리적 페이지 목록을 가상 공간에서 연속적으로 나타나게 하기 위해 MMU(Memory Mapping Unit)라는 하드웨어는 아래 그림과 같이 페이지 테이블을 사용하여 가상 주소(응용 프로그램용)를 물리적 주소(실제 메모리 액세스용)로 변환합니다. 페이지가 가상 공간에 존재하지 않는 경우(따라서 MMU 테이블에 없는 경우) MMU는 해당 페이지에 신호를 보내 존재하지 않는 메모리 영역에 대한 액세스를 보고하는 기본 메커니즘을 제공합니다. 이는 결국 시스템에서 스와핑이나 동적 페이지 인스턴스화와 같은 고급 메모리 프로그래밍을 구현하는 데 사용됩니다. MMU는 메모리에 대한 CPU 액세스에만 효과적이므로 가상 주소는 물리적 주소와 일치시킬 방법이 없으므로 하드웨어 독립적입니다.

MMU 및 IOMMU.
MMU는 CPU 액세스에만 적합하지만 주변 장치에는 IOMMU와 같은 기능이 있습니다. 위 그림에서 볼 수 있듯이 IOMMU는 주변 장치의 주소 공간을 가상화한다는 점을 제외하면 MMU와 동일합니다. IOMMU는 마더보드 칩셋(모든 주변 장치 간에 공유되는 경우) 또는 그래픽 카드 자체(그래픽 카드 자체에서는 AGP GART, PCI GART라고 함)의 다양한 형태로 볼 수 있습니다. IOMMU의 역할은 주변 장치의 메모리 주소를 물리적 주소로 변환하는 것입니다. 특히 더 나은 보안 및 하드웨어 가상화에 필요한 특정 메모리 범위로 DMA를 제한하도록 장치를 "속일" 수 있습니다.
IOMMU의 특별한 경우는 Linux swiotlb로, 부팅 시 연속적인 물리적 메모리를 할당하고(아직 조각화가 없기 때문에 대규모의 연속적인 물리적 할당이 가능함) 이를 DMA에 사용합니다. 메모리는 물리적으로 연속되어 있고 페이지 변환이 필요하지 않으므로 해당 메모리 범위 내에서 DMA가 수행될 수 있습니다. 그러나 이는 이 메모리(기본적으로 64MB)가 사전 할당되어 다른 용도로 사용되지 않음을 의미합니다.
AGP GART는 그래픽 카드에 선형 영역을 표시하기 위해 AGP 그래픽 카드와 함께 사용되는 IOMMU의 또 다른 특수 사례입니다. 이 경우 IOMMU는 마더보드의 AGP 칩셋에 내장되어 있습니다. AGP GART 영역은 가상 메모리의 선형 영역으로 시스템에 노출됩니다.
IOMMU의 또 다른 특별한 경우는 일부 GPU의 PCI GART로, 이를 통해 시스템 메모리 블록을 카드에 노출할 수 있습니다. 이 경우 IOMMU 테이블은 그래픽 카드에 내장되어 있으며 일반적으로 사용되는 물리적 메모리는 연속될 필요가 없습니다.
분명히 메모리 유형이 너무 다양하기 때문에 성능이 균일하지 않으며 주로 CPU, GPU 또는 버스 전송이 포함되는지 여부에 따라 모든 액세스 조합이 빠른 것은 아닙니다. 또 다른 문제는 메모리 일관성입니다. 메모리가 장치 전체에서 일관되게 유지하는 방법, 특히 CPU에서 쓴 데이터를 GPU에서 사용할 수 있도록(또는 그 반대로) 보장하는 방법입니다. 성능이 높을수록 일반적으로 메모리 일관성 수준이 낮아지고 그 반대의 경우도 마찬가지이기 때문에 이 두 가지 질문은 관련이 있습니다.
메모리 캐시 매개변수 설정 측면에서 메모리 범위에 대한 캐시 속성을 설정하는 방법에는 두 가지가 있습니다.
-MTRR. MTRR(Memory Type Range Register)은 주어진 물리적 메모리 범위의 속성을 설명하는 레지스터입니다. 각 MTRR에는 시작 물리적 주소, 크기 및 캐시 유형이 포함됩니다. MTRR의 양은 시스템에 따라 다르지만 매우 제한적입니다. 물리적 메모리 범위에 적용 가능하지만 해당 효과는 해당 가상 메모리 페이지에 적용됩니다. 예를 들어 페이지는 특정 캐시 유형으로 매핑될 수 있습니다.
- PAT(페이지 속성 테이블)를 사용하면 페이지별 메모리 속성을 설정할 수 있습니다. 제한된 수의 메모리 범위에 의존하는 MTRR과 달리 캐시 속성은 페이지별로 지정할 수 있습니다. 그러나 이는 최신 x86 프로세서에서만 사용할 수 있는 확장입니다.
이 외에도 일부 아키텍처에서는 명시적 캐시 명령어를 사용할 수 있습니다. 예를 들어 x86에서 movntq는 캐시되지 않은 mov 명령어이고 clflush는 캐시 라인을 선택적으로 플러시할 수 있습니다.
MTRR 및 PAT 시스템 메모리에는 세 가지 캐시 모드를 사용할 수 있습니다.
UC(UnCached) 메모리는 캐시되지 않습니다. 이 영역에 대한 CPU 읽기/쓰기는 캐시되지 않으며 각 메모리 쓰기 명령은 실제 즉시 메모리 쓰기를 트리거합니다. CPU/GPU 경합 상황을 방지하기 위해 정보가 실제로 기록되었는지 확인하는 데 도움이 됩니다.
WC(Write Combine) 메모리는 캐시되지 않지만, CPU 쓰기는 함께 결합되어 성능을 향상시킵니다. 캐시되지 않은 메모리가 필요하지만 쓰기를 그룹화해도 성능에 부정적인 영향을 미치지 않는 상황에서 성능을 향상시키는 데 적합합니다.
WB(Write Back) 메모리가 캐시되었습니다. 최상의 CPU 액세스 성능을 얻기 위한 기본 모드입니다. 그러나 제한된 시간 후에 메모리 쓰기가 중앙 메모리로 전파된다는 보장은 없습니다.
위의 캐시 모드는 CPU 전용이며 GPU 액세스는 현재 캐시 모드의 직접적인 영향을 받지 않습니다. 그러나 GPU가 이전에 CPU로 채워졌던 메모리 영역에 액세스해야 하는 경우 캐시되지 않은 모드를 사용하면 메모리 쓰기가 실제로 완료되고 CPU 캐시에 머무르지 않습니다. 동일한 효과를 얻는 또 다른 방법은 일부 x86 프로세서(예: cflush)에서 캐시 플러시 명령을 사용하는 것이지만 캐시 모드를 사용하는 것보다 이식성이 떨어집니다. 또 다른 (이식 가능한) 접근 방식은 메모리 장벽을 사용하는 것입니다. 이를 통해 보류 중인 메모리 쓰기가 계속되기 전에 주 메모리에 커밋되도록 합니다.
분명히 다양한 캐싱 모드를 사용하면 모든 액세스가 동일하게 수행되는 것은 아닙니다.
캐시되지 않은 모드는 CPU가 시스템 메모리에 액세스할 때 최악의 성능을 제공하고, 쓰기 저장은 최고의 성능을 제공하며, 쓰기 조합은 그 사이 어딘가에 있습니다.
CPU가 개별 카드에서 비디오 메모리에 액세스하는 경우 각 액세스에는 버스 사이클이 필요하므로 읽기 또는 쓰기 여부에 관계없이 모든 액세스가 매우 느립니다. 따라서 CPU를 사용하여 VRAM의 넓은 영역에 액세스하는 것은 권장되지 않습니다. 또한 일부 GPU에서는 동기화가 필요합니다. 그렇지 않으면 GPU가 중단될 수 있습니다.
분명히 GPU는 VRAM에 매우 빠르게 액세스합니다.
시스템 RAM에 대한 GPU 액세스는 캐시 모드의 영향을 받지 않지만 DMA 트랜잭션의 경우처럼 여전히 버스를 통과해야 합니다. 모두 비동기식으로 발생하므로 CPU 관점에서는 "무료"라고 간주할 수 있지만 각 DMA 트랜잭션에는 무시할 수 없는 설정 비용이 포함됩니다. 이것이 바로 소량의 메모리를 전송할 때 DMA 트랜잭션이 직접 CPU 액세스보다 항상 나은 것은 아닌 이유입니다.
마지막으로 메모리에 대한 마지막 중요한 점은 메모리 장벽과 쓰기 게시의 개념입니다. 캐시된(쓰기 병합 또는 쓰기 저장) 메모리 영역의 경우 메모리 장벽은 보류 중인 쓰기 작업이 실제로 메모리에 커밋되도록 보장합니다. 이 옵션은 예를 들어 GPU에 특정 메모리 영역을 읽도록 요청하기 전에 사용됩니다. I/O 영역의 경우 원장에 쓰기라는 유사한 기술이 존재합니다. 이는 I/O 영역 내에서 더미 읽기를 수행하는 것으로 구성되며, 부작용으로 완료되기 전에 보류 중인 쓰기가 적용될 때까지 기다립니다.

PCI Express의 고유한 그래픽 카드를 갖춘 클래식 데스크탑 컴퓨터 아키텍처. 메모리 기술의 일반적인 대역폭에서 메모리 대기 시간이 부족하기 때문에 GPU와 CPU 간에는 제로 복사가 불가능합니다. 둘 다 자체 별도의 물리적 메모리를 갖고 있고 데이터를 공유하려면 한 곳에서 다른 곳으로 데이터를 복사해야 하기 때문입니다.

파티션된 메인 메모리가 있는 통합 그래픽: 시스템 메모리의 일부가 GPU에만 할당되며, 제로 복사는 불가능합니다. 데이터는 시스템 메모리 버스를 통해 한 파티션에서 다른 파티션으로 복사되어야 합니다.

AMD Kaveri 또는 PlayStation 4(HSA)에서 볼 수 있는 통합 메인 메모리가 포함된 통합 그래픽.
16.2.5 PFIFO
대부분의 엔진 명령은 PFIFO라는 특수 엔진을 통해 전송됩니다. PFIFO는 채널 또는 FIFO라고 불리는 여러 개의 완전히 독립적인 명령 대기열을 유지 관리합니다. 각 채널은 MMIO[GF100 이전] 또는 VRAM[GF100+]의 영역인 "채널 제어 영역"을 통해 제어됩니다. PFIFO는 이 영역으로 들어오는 모든 채널을 차단하고 이에 대한 조치를 취합니다.
PFIFO는 내부적으로 채널 간 시간 공유를 수행하지만 이는 애플리케이션에 투명합니다. PFIFO에 의해 제어되는 엔진은 채널을 알고 있으며 각 채널에 대해 별도의 컨텍스트를 유지합니다.
PFIFO의 컨텍스트 전환 기능은 카드의 차세대 버전에 따라 달라집니다. NV40에서 PFIFO는 기본적으로 언제든지 채널 간을 전환합니다. 이전 카드에서는 캐시된 백업 저장소가 없기 때문에 캐시가 비어 있는 경우에만 전환이 가능했습니다. 그러나 PFIFO로 제어되는 엔진은 전환 성능이 훨씬 낮습니다. 명령 간에만 전환할 수 있습니다. 이 접근 방식은 이전 카드에서는 큰 문제가 아니었지만(명령은 제한된 시간 동안 실행되도록 보장되었으므로) 루핑 기능을 갖춘 프로그래밍 가능한 셰이더를 도입하면 장기 실행 셰이더를 실행하여 전체 GPU를 효과적으로 중단시킬 수 있습니다.
PFIFO는 대략 4가지 부분으로 나눌 수 있습니다.
PFIFO 푸셔: 사용자 명령을 수집하여 주입합니다.
PFIFO 캐시: 실행을 기다리는 수많은 명령.
PFIFO 풀러: 명령을 실행하고 이를 적절한 엔진이나 드라이버에 전달합니다.
PFIFO 스위처: 채널의 타임 슬라이스를 표시하고 PFIFO 레지스터와 RAMFC 메모리 사이의 채널 상태를 저장/복원합니다.
채널은 다음 부분으로 구성됩니다.
채널 모드: PIO[NV1:GF100], DMA[NV4:GF100] 또는 IB[G80-].
PFIFO DMA 푸셔 상태[DMA 및 IB 채널만 해당].
PFIFO 캐시 상태: 명령이 승인되었지만 아직 실행되지 않았습니다.
PFIFO 풀러 상태.
RAMFC: PFIFO의 채널이 현재 활성 상태가 아닐 때 위의 정보가 저장되는 VRAM 영역[사용자에게 표시되지 않음].
RAMHT [GF100 이전 버전만 해당]: 채널에서 사용할 수 있는 "객체" 테이블입니다. 개체는 DMA 개체(NV3 DMA 개체, NV4:G80 DMA 개체, DMA 개체 참조) 또는 엔진 개체일 수 있는 32비트 핸들로 식별됩니다. G80 이전 카드에서는 채널 간에 개별 개체를 공유하는 것이 가능했습니다.
vspace(G80+만 해당): 채널 명령을 실행할 때 엔진에 표시되는 가상 메모리 공간을 설명하는 페이지 테이블의 계층 구조입니다. 여러 채널이 하나의 vspace를 공유할 수 있습니다.
엔진별 상태.
채널 모드는 명령이 채널에 제출되는 방식을 결정합니다. PIO 모드는 GF100 이전 카드에서 사용할 수 있으며 이러한 방법을 채널 제어 영역에 직접 연결해야 합니다. 느리고 깨지기 쉬우므로 여러 채널을 동시에 사용할 때 오류가 발생하기 쉬우므로 권장되지 않습니다. NV1:NV40에서는 모든 채널이 PIO 모드를 지원합니다. NV40:G80에서는 처음 32개 채널만 PIO 모드를 지원합니다. G80에서: GF100은 채널 0에서만 PIO 모드를 지원합니다.
16.2.6 그래픽 카드 분석
오늘날 그래픽 카드는 기본적으로 컴퓨터 내의 컴퓨터입니다. 별도의 카드에 전용 프로세서가 있고 자체 컴퓨팅 장치, 버스, 메모리가 있는 복잡한 괴물입니다. 이 섹션에서는 다음 요소를 포함하여 그래픽 카드에 대한 개요를 제공합니다.
- 그래픽 메모리
GPU의 메모리(비디오 메모리)는 실제, 전용, 온카드 메모리(개별 카드의 경우) 또는 CPU와 공유되는 메모리(통합 카드의 경우 "도난된 메모리" 또는 "조각된 메모리"라고도 함)일 수 있습니다. 공유 메모리 사례에는 흥미로운 의미가 있습니다. 시스템에서 비디오로의 메모리 복사가 제대로 구현되면 사실상 무료이기 때문입니다. 전용 메모리의 경우 이는 앞뒤로 전송이 필요하며 버스 속도에 의해 제한된다는 의미입니다.
최신 GPU에는 다양한 리소스(시스템 메모리의 실제 비디오 메모리)를 GPU 주소 공간에 매핑할 수 있는 가상 메모리 형태도 있습니다. 이는 CPU의 가상 메모리와 매우 유사하지만 완전히 별도의 하드웨어를 사용하여 구현됩니다. 예를 들어, 구형 Radeon 카드(실제로는 Rage 128)에는 GPU 주소 공간에 매핑할 수 있는 여러 표면이 있으며, 각 표면은 연속적인 메모리 리소스(비디오 램, AGP, PCI)입니다. 이전 Nvidia 카드(NV40 이전의 모든 카드)는 비슷한 개념을 가지고 있었는데, 이는 주어진 목적에 바인딩될 수 있는 메모리 영역을 설명하는 개체를 기반으로 했습니다. 최신 그래픽 카드(NV50 및 R800부터 시작)를 사용하면 옵션 시스템 및 전용 비디오 메모리 페이지를 사용하여 페이지별로 주소 공간을 구축할 수 있습니다. 매핑되지 않은 페이지 액세스가 인터럽트를 통해 시스템에 신호를 보내고 비디오 메모리 페이지 오류 처리기에서 실행될 수 있다는 사실과 마찬가지로 CPU 가상 주소 공간과의 유사성은 놀랍습니다. 그러나 드라이버 개발자는 근본적으로 다른 CPU와 GPU의 여러 주소 공간을 처리해야 하므로 이러한 문제를 주의해서 처리해야 합니다.
- 표면
표면은 모든 렌더링의 기본 소스이자 대상입니다. 이름은 다르지만(텍스처, 렌더 대상, 버퍼...) 기본 아이디어는 항상 동일합니다. 다음 그림은 그래픽 화면의 레이아웃을 보여줍니다. 하드웨어 제한(보통 2의 다음 배수)으로 인해 표면 너비는 피치라고 부르는 값으로 반올림되므로 사용되지 않는 픽셀의 데드 스페이스가 있습니다.

그래픽 표면에는 다음과 같은 많은 특성이 있습니다.
표면의 픽셀 형식입니다. 픽셀의 색상은 빨간색, 녹색, 파란색 구성 요소와 혼합 불투명도로 사용되는 알파 구성 요소로 표시됩니다. 전체 픽셀의 비트 수는 일반적으로 하드웨어 크기(8, 16 또는 32비트)와 일치하지만 4개 구성 요소 간의 비트 재분배는 하드웨어 크기와 반드시 일치하지는 않습니다. 각 픽셀에 사용되는 비트 수를 픽셀당 비트 수 또는 bpp라고 합니다. 일반적인 픽셀 형식에는 888 RGBX, 8888 RGBA, 565 RGB, 5551 RGBA 및 4444 RGBA가 포함됩니다. 요즘 대부분의 그래픽 카드는 8888에서 기본적으로 작동합니다.
너비와 높이는 픽셀 단위로 측정되는 가장 확실한 특징입니다.
간격은 데드존 픽셀을 포함한 표면의 바이트 단위(픽셀 단위가 아님!) 너비입니다. 피치는 메모리 사용량 계산을 용이하게 합니다. 예를 들어 데드존을 포함하려면 표면 크기를 높이 x 너비 x bpp가 아닌 높이 x 피치로 계산해야 합니다.
표면은 항상 비디오 메모리에 선형으로 저장되지는 않습니다. 실제로 성능상의 이유로 표면은 선형으로 저장되지 않는 경우가 많습니다. 이렇게 하면 렌더링 시 메모리 액세스 위치가 향상되기 때문입니다. 이러한 유형의 표면을 타일 표면이라고 합니다. 타일 표면의 정확한 레이아웃은 하드웨어에 따라 크게 다르지만 일반적으로 Z 곡선(아래의 Z 순서 곡선, Morton 곡선이라고도 함) 또는 힐베르트 곡선(아래)과 같은 공간 채우기 곡선입니다.


또한 Morton 및 Hilbert 곡선은 3D 공간 탐색도 지원합니다.

- 2D 엔진
2D 엔진 또는 블리터는 2D 가속에 사용되는 하드웨어입니다. Blitter는 그래픽 가속의 초기 형태 중 하나였으며 오늘날에도 여전히 매우 일반적입니다. 일반적으로 2D 엔진은 다음 작업을 수행할 수 있습니다.
블릿. BLIT는 GPU가 한 위치에서 다른 위치로 메모리 직사각형의 복사본을 만드는 곳이며 소스와 대상은 비디오 또는 시스템 메모리일 수 있습니다.
견고한 패딩. 단색 채우기에는 직사각형 메모리 영역을 색상으로 채우는 작업이 포함되며 여기에는 알파 채널도 포함될 수 있습니다.
알파 블릿. Alpha Blit은 투명도를 얻기 위해 표면 픽셀의 알파 구성 요소를 사용합니다.
스트레치 사본.
아래 이미지는 서로 다른 두 표면 사이의 직사각형을 결합하는 예를 보여줍니다. 이 작업은 소스 및 대상 좌표, 소스 및 대상 피치, 블릿 너비 및 높이 등의 매개변수로 정의됩니다. 그러나 2D 좌표로 제한되므로 일반적으로 원근감이나 변환을 위해 블리팅 엔진을 사용할 수 없습니다.

두 개의 겹치는 소스 표면과 대상 표면 사이에 블릿이 발생하면 복사본의 의미를 정의하기가 쉽지 않습니다. 특히 블릿에서 발생하는 일이 단순한 직사각형 이동이 아니라 코어의 픽셀별 이동이라고 고려할 때 더욱 그렇습니다. 아래 이미지와 같이 위에서 아래로 한줄씩 복사하면 부작용으로 일부 소스 픽셀이 수정됩니다. 따라서 복사 방향의 개념이 blitter에 도입되었습니다. 이 경우 올바른 사본을 얻으려면 상향식 사본이 필요합니다. 일부 카드는 표면 겹침(예: NVIDIA GPU)을 기반으로 복사 방향을 자동으로 결정하지만 다른 카드는 그렇지 않습니다. 이 경우 드라이버에서 이를 처리해야 합니다. 이것이 바로 일부 GPU가 2D 엔진에 물러서도록 지시하기 위해 실제로 음의 피치를 지원하는 이유입니다.

마지막으로, 현재의 모든 그래픽 가속기에 2D 엔진이 있는 것은 아닙니다. 3D 가속은 기술적으로 2D 가속의 상위 집합이므로 3D 엔진을 사용하여 2D 가속을 구현할 수 있습니다. 실제로 일부 드라이버는 3D 엔진을 사용하여 2D를 구현하므로 GPU 제조업체는 2D 전용 트랜지스터를 완전히 포기할 수 있습니다. 그러나 일부 다른 카드는 트랜지스터 전용이 아니라 GPU 내부의 3D 작업 위에 2D 작업을 마이크로프로그래밍합니다(이는 Radeon R600 시리즈의 3D 위에 2D를 구현하는 선택적 펌웨어가 있는 nv10 이후의 nVidia 카드와 nv50 이전의 nVidia 카드의 경우입니다). 2D와 3D 작업의 혼합은 이제 하드웨어 장치를 공유하므로 영향을 받는 경우가 있습니다.
- 3D 엔진
3D 엔진은 래스터라이제이션 엔진이라고도 합니다. 여기에는 버텍스->기하학->조각, 그래픽 FIFO, DMA 등과 같은 파이프라인(단방향) 방식으로 데이터를 교환하는 일련의 단계가 포함되어 있습니다. 텍스처와 표면은 더 나은 캐시 위치를 위해 타일링되는 경우가 많습니다. 타일링이란 텍스처가 GPU 메모리에 선형적으로 저장되지 않고 메모리에 저장되어 텍스처 공간에서 가까운 픽셀이 Z 순서 곡선 및 힐베르트 곡선과 같이 메모리 공간에서도 가깝다는 것을 의미합니다.
- 오버레이 및 하드웨어 스프라이트.
스캔 출력: 그래픽 디스플레이의 마지막 단계는 디스플레이 장치나 화면에 정보를 표시하는 것입니다. 디스플레이 장치는 그래픽 체인의 마지막 링크이며 사용자에게 그림을 보여주는 역할을 합니다.
또한 이 기사에서는 디지털 및 아날로그 신호, hsync, vsync, green sync, 커넥터 및 인코더(CRTC, TMD, LVDS, DVI-I, DVI-A, DVI-D, VGA)와 같은 기술이 무시됩니다.
16.2.7 그래픽 카드 프로그래밍
각 PCI 카드는 여러 PCI 리소스를 노출합니다. lspci-v는 BIOSS, MMIO 범위, 비디오 메모리(또는 그 일부만)를 포함하되 이에 국한되지 않는 이러한 리소스를 나열합니다. 총 PCI 리소스 크기가 제한되어 있기 때문에 일반적으로 카드는 비디오 메모리의 일부만 리소스로 노출할 수 있으며 나머지 메모리에 액세스하는 유일한 방법은 액세스 가능한 다른 영역의 DMA(점프 페이지와 유사한 방식)를 통해서입니다. PCI 리소스 공간은 여전히 제한되어 있는 반면 비디오 메모리 크기는 계속해서 증가함에 따라 이러한 상황은 점점 더 일반화되고 있습니다.
- MMIO
MMIO는 카드에 대한 가장 직접적인 액세스 방법입니다. 일련의 주소가 CPU에 노출되고 각 쓰기 작업이 GPU로 직접 전달되므로 CPU에서 GPU로의 명령 통신이 가장 간단해집니다. 이러한 종류의 프로그래밍은 동기식입니다. 쓰기는 CPU에 의해 수행되고 GPU에서 고정 단계로 실행되므로 각 액세스가 버스에서 패킷으로 바뀌고 CPU는 후속 명령을 제출하기 전에 이전 GPU 명령이 완료될 때까지 기다려야 하기 때문에 성능이 수준 이하로 떨어집니다. 따라서 MMIO는 오늘날 드라이버의 성능에 중요하지 않은 경로에만 사용됩니다.
- DMA
DMA(직접 메모리 액세스)는 버스의 버스 마스터 기능을 사용하는 주변 장치를 말하며, CPU의 개입 없이 하나의 주변 장치가 다른 주변 장치와 직접 통신할 수 있도록 합니다. 그래픽 카드의 경우 DMA의 가장 일반적인 두 가지 용도는 다음과 같습니다.
GPU와 시스템 메모리 간 전송(텍스처 읽기 및 버퍼 쓰기용) AGP 또는 PCI를 통한 텍스처 구현은 물론 하드웨어 가속 텍스처 전송도 가능합니다.
FIFO 명령을 실행합니다. CPU와 GPU 사이의 MMIO는 동기식이며 그래픽 드라이버 자체가 많은 I/O를 사용하므로 카드와 통신하는 더 빠른 방법이 필요합니다. FIFO 명령은 그래픽 카드와 CPU 간에 공유되는 메모리 블록(시스템 메모리 또는 드물게는 비디오 메모리)입니다. 여기서 CPU는 GPU가 나중에 실행할 수 있도록 명령을 내리고 GPU는 DMA를 사용하여 FIFO를 비동기적으로 읽고 명령을 실행합니다. 이 모델을 사용하면 CPU 및 GPU 명령 스트림의 비동기 실행이 가능해 성능이 향상됩니다.
- 인터럽트
인터럽트는 하드웨어 주변 장치, 특히 GPU가 CPU에 이벤트를 알리는 방법인 경우가 많습니다. 인터럽트 사용의 예로는 그래픽 명령 완료 신호 보내기, 수직 귀선소거 이벤트 신호 보내기, GPU 오류 보고 등이 있습니다.
주변 장치가 인터럽트를 발생시키면 CPU는 다른 현재 실행을 선점하는 인터럽트 핸들러라는 작은 루틴을 실행합니다. 인터럽트 핸들러에는 최대 실행 시간이 있으므로 드라이버는 이를 짧게(몇 마이크로초 이하) 유지해야 합니다. 더 많은 코드를 실행하기 위한 일반적인 해결책은 인터럽트 핸들러에서 작은 작업(태스크릿)을 예약하는 것입니다.
16.2.8 그래픽 하드웨어 케이스
- 포워드 렌더링
포워드 렌더러(즉, 클래식 렌더러)는 3차원 프리미티브를 렌더링하는 가장 직접적인 방법입니다. 그래픽 API를 GPU에 하나씩 제출하여 형상을 그리고 이 프로세스를 반복합니다. 대부분의 모바일 GPU에서 사용되는 방식입니다.
NVidia 하드웨어는 다른 아키텍처에 비해 몇 가지 특징이 있습니다. 첫 번째는 다중 명령 FIFO(일부 고급 인피니밴드 네트워크 카드의 기능과 유사)와 컨텍스트 전환 메커니즘을 사용하여 이러한 FIFO 간의 전환을 달성하는 다중 컨텍스트의 가용성입니다. 컨텍스트 간의 컨텍스트 전환에는 소형 펌웨어가 사용되며 그래픽 카드 상태를 메모리의 한 부분에 저장하고 다른 컨텍스트를 복원하는 역할을 합니다. 라운드 로빈 알고리즘을 사용하는 스케줄링 시스템은 컨텍스트 선택을 처리하며 시간 조각은 프로그래밍 가능합니다.
두 번째 특징은 그래픽 객체의 개념입니다. Nvidia 하드웨어에는 두 가지 수준의 GPU 액세스가 있습니다. 첫 번째 수준은 컨텍스트 전환에 사용되는 기본 수준입니다. 두 번째는 고급 기능(예: 2D 또는 3D 가속)을 활성화하기 위해 기본 수준을 마이크로 프로그래밍하는 그래픽 개체입니다.
- 디퍼드 렌더링
디퍼드 렌더러는 GPU의 다른 디자인입니다. 드라이버는 이를 메모리에 저장하고 렌더 API 제출 시 각 3D 기본 요소를 렌더링하는 대신 프레임 끝을 확인하면 단일 하드웨어 호출을 실행하여 전체 장면을 렌더링합니다. 디퍼드 렌더링은 기존 아키텍처에 비해 많은 장점이 있습니다.
화면을 타일(보통 16 x 16 ~ 32 x 32 픽셀 범위)로 분할하면 더 나은 렌더링 위치를 얻을 수 있습니다. 그런 다음 GPU는 이러한 타일을 반복할 수 있으며 각 타일에 대해 내부(미니) z버퍼에서 픽셀당 깊이를 확인할 수 있습니다. 전체 타일이 렌더링되면 비디오 메모리에 다시 쓸 수 있어 귀중한 대역폭을 절약할 수 있습니다. 마찬가지로, 가시성은 텍스처 데이터를 가져오기 전에 결정되므로 유용한 텍스처 데이터만 읽히고(역폭 절약) 조각 셰이더는 보이는 조각에서만 실행됩니다(컴퓨팅 성능 절약).
깊이 버퍼 값이 필요하지 않으면 메모리에 쓸 필요가 없습니다. 깊이 버퍼 해상도는 GPU 내의 모든 타일에 구현될 수 있으며 비디오 메모리에 다시 기록되지 않으므로 비디오 메모리 대역폭과 공간이 절약됩니다.
물론 타일 렌더링을 사용하려면 그리기를 시작하기 전에 전체 장면을 메모리에 저장해야 하며, 그리기를 시작하기 전에 프레임이 끝날 때까지 기다려야 하기 때문에 대기 시간도 늘어납니다. 드라이버가 애플리케이션이 다음 프레임에 대한 데이터를 제출하도록 이미 허용한 경우 GPU에서 지정된 프레임을 그려 지연 문제를 부분적으로 숨길 수 있습니다. 그러나 일부 경우(다시 읽어오기, 프로세스 간 동기화) 이를 방지하는 것이 항상 가능한 것은 아닙니다.
지연 렌더러는 대역폭이 매우 부족한 임베디드 플랫폼에 특히 유용하며 애플리케이션이 매우 단순하므로 메서드의 추가 대기 시간과 제한 사항이 중요하지 않습니다. SGX는 디퍼드 렌더링 GPU의 예입니다. 청크 구조를 사용합니다. SGX 셰이더는 블렌딩과 깊이 테스트를 결합합니다. 지연 렌더러의 또 다른 예는 Mali GPU 시리즈입니다.
요약하자면, 컴퓨터에는 여러 메모리 도메인이 있으며 일관성이 없습니다. GPU는 자체 버스, 주소 공간 및 컴퓨팅 장치를 갖춘 완전히 독립적인 컴퓨터입니다. CPU와 GPU 간의 통신은 버스를 통해 이루어지며 이는 성능에 매우 중요한 영향을 미칩니다. GPU는 MMIO와 명령 FIFO의 두 가지 모드를 사용하여 프로그래밍할 수 있습니다. 디스플레이 장치에 대한 표준 출력 방법은 없습니다.
16.3 운영 체제 그래픽 드라이버
16.3.1 Windows 그래픽 드라이버
16.3.1.1 WDDM 개요
Windows 그래픽 드라이버는 IHV(Intel, NVIDIA, AMD, Qualcomm, PowerVR, VIA, Matrox 등)에 의해 구현 및 유지 관리되며 매우 풍부한 드라이버입니다. 기본 폴백(기본 렌더링, 기본 디스플레이)을 지원하고, 최소 드라이버 기능을 구현하며, 가상화(VMware, Virtual Box, Parallels 드라이버), 원격 데스크톱 솔루션(XenDesktop, RDP 등), 가상 디스플레이(인텔리그래픽, 엑스트라몬 등)도 지원합니다.
WDDM(Windows 디스플레이 드라이버 모델)은 사용자 모드와 커널 모드로 구분됩니다. 사용자 모드로의 전환은 안정성과 신뢰성을 위한 것입니다.

사용자 모드와 커널 모드 구성 요소 간의 통신.
Vista 이전의 대부분의 블루 스크린은 그래픽 드라이버(MSDN)로 인해 발생했습니다. "Windows XP에서는 크고 복잡한 디스플레이 드라이버가 시스템 불안정의 주요 원인이 될 수 있습니다. 이러한 드라이버는 완전히 커널 모드(즉, 시스템 코드 깊숙한 곳)에서 실행되므로 드라이버 문제로 인해 전체 시스템이 다시 시작되는 경우가 많습니다. Windows XP 기간 동안 수집된 오류 분석 데이터에 따르면 디스플레이 드라이버는 모든 블루 스크린의 20%를 차지했습니다."
대부분의 프로세스에서 사용자 모드 부분은 dll의 일부로 실행되며 여전히 표면(인코더/디코더, 바이너리 이식)에 액세스할 수 있으며 일부 API는 원격 액세스 표면(예: WebGL)에 부분적으로(또는 간접적으로) 노출될 수 있습니다. 아래 다이어그램은 WDDM을 지원하는 데 필요한 아키텍처를 보여줍니다.


Windows 드라이버 모델의 진화 역사는 다음과 같습니다.
윈도우 XP: XPDM.
윈도우 비스타: WDDM 1.0, DWM 및 Aero.

DWM이 없는 경우와 dWM이 있는 경우의 비교입니다. DWM은 바탕 화면 구성을 처리하므로 각 프로그램이 자체 디스플레이를 추적해야 하는 경우 새 기능을 사용할 수 없습니다. 작업 표시줄의 Aero Peek, 맨 위 창 뒤에 있는 응용 프로그램을 볼 수 있는 Aero Glass, 방향을 쉽게 변경할 수 있는 기능. "작업 표시줄에 핀치" 효과를 포함하여 많은 새로운 Windows 애니메이션이 DWM을 사용합니다.
Windows 7: WDDM 1.1, 추가 DWM.
Windows 8: WDDM 1.2, XPDM 지원이 제거되었습니다.
윈도우 8.1: WDDM 1.3.
윈도우 10: WDDM 2.0.
16.3.1.2 WDDM 방식
초기 Windows 버전(예: Vista)에서 그래픽/게임/멀티미디어/렌더링 스택 아키텍처는 다음과 같습니다.

단순화된 아키텍처 다이어그램은 다음과 같습니다.

Windows Vista의 그래픽 코어는 다음과 같습니다.

그 중 Windows 디스플레이 드라이버 모델(WDDM, Windows Display Driver Model) 관련 모듈은 다음과 같습니다.

WDDM은 모든 그래픽의 초석입니다. 기본 원리는 그래픽 기능이 정상이라는 것입니다. 전체 드라이버 스택은 10년간의 개발을 통합하기 위해 재설계되었습니다. 새로운 드라이버 모델은 안정성, 보안, 가용성(애플리케이션 가상화) 및 성능을 고려합니다.
그래픽 API의 경우 다음과 같은 여러 버전의 초기 WDDM이 있습니다.




Window 창 관리의 경우 아키텍처는 다음과 같습니다.


Windows 그래픽 드라이버 모델 모든 Windows 사용자를 위한 단일 그래픽 드라이버 모델인 그래픽 드라이버 모델은 사용자 경험을 향상시키고, 혁신을 통해 새로운 시각적 및 컴퓨팅 시나리오를 가능하게 하며, 성능 및 안정성 향상을 통해 Windows는 다양한 폼 팩터에 걸쳐 확장할 수 있습니다. 아래 두 그림의 분포는 Windows 7과 8의 비교를 보여줍니다.

WDDM 1.2 기능 세트:
- 향상된 사용자 경험: 입체 3D 경험, 부드러운 화면 회전, 원활한 시작 및 복구, 디스플레이 "컨테이너 ID" 지원.

원활한 부팅, 복구 및 드라이버 업그레이드.

Windows 8에서 더 빠른 절전 및 재개 - 통합 GPU.
- 향상된 성능: GPU 우선순위 지정, 절전 및 다시 시작 최적화, 비디오 메모리 프로비저닝 및 재활용 API, DDI, 세분화된 장치 전원 관리, SoC 최적화, 타일 기반 렌더링 최적화.

데스크톱 및 터치 반응성이 향상되었습니다. 빠르고 부드러운 지하철 스타일과 터치 경험으로 세밀한 GPU 선점을 지원합니다. 선점이 미세할수록 응답 속도가 빨라집니다.

*비디오 메모리 제공 및 재활용 API입니다. 개선된 비디오 메모리 할당 체계, 이점: 애플리케이션을 위한 개선된 비디오 메모리 가용성, 새로운 D3D API 및 WDDM DDI
:D3D 애플리케이션, WDDM 1.2 드라이버. *

구성요소 전원 관리.

직접 뒤집기. 에너지 효율성을 위해 데스크탑 구성을 최적화하고 비디오 프레임 재생 중에 메모리 사본을 저장합니다.

타일 기반 렌더링 최적화. TBR에 최적화된 그래픽 스택인 TBR GPU의 인기가 높아지면서 전력을 절약하고 메모리 대역폭 사용량을 최소화하며 타일링을 줄입니다.
- 신뢰성 향상: GPU 내결함성이 향상되어 개발자와 시스템 빌더에게 서버를 다시 시작하지 않고도 더 나은 진단 및 드라이버 업그레이드 기능을 제공합니다.

GPU 내결함성이 향상되었습니다. 왼쪽: Windows 7, 이전 OS, 글로벌 TDR, 모든 그래픽 애플리케이션 재설정 및 다시 시작에 대한 시간 초과 감지 및 복구 개선. 오른쪽: Windows 8의 GPU 정지 감지, 선점 시간 초과, 장기 실행 작업 실행 기능, 엔진별 TDR.
요약하면, Windows 8용 WDDM은 시각적으로 풍부하고 빠르고 원활한 최종 사용자 경험을 제공하여 다양한 폼 팩터에 걸쳐 새로운 경험을 제공하고 성능을 최적화하는 동시에 전력을 절약하고 성능 도구를 활용하여 그래픽 드라이버를 조정합니다.
현재 WDDM의 드라이버 아키텍처는 다음과 같습니다.

다음은 D3D의 렌더링 작업 흐름에 대한 예시 다이어그램입니다.


다음 그림은 WDDM의 디스플레이 미니포트 드라이버에 대해 스레드 동기화가 작동하는 방식을 보여줍니다.

16.3.1.3 WDDM 인터페이스
kmd 드라이버는 WDDM의 커널 모드 모듈 중 하나이며 다음과 같습니다.
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
(...)
DRIVER_INITIALIZATION_DATA DriverInitializationData;
(...)
DriverInitializationData.DxgkDdiEscape = DDIEscape;
(...)
Status = DxgkInitialize(DriverObject, RegistryPath, &DriverInitializationData);
(...)
}WDDM kmd 드라이버는 동기화될 때 이러한 콜백에 대한 스레딩 모델을 제공합니다. 이는 기본적으로 4개 수준으로 구성됩니다(각 콜백은 각 수준 중 하나에 속함).
3: 하나의 스레드만 들어갈 수 있고, GPU는 유휴 상태여야 하며, 처리 중인 DMA 버퍼가 없으며, 비디오 메모리가 호스트 CPU 메모리로 제거됩니다.
2: 비디오 메모리가 밖으로 이동된다는 점을 제외하면 3과 동일합니다.
1: 호출은 클래스로 분류되며, 클래스당 하나의 스레드만 동시에 콜백을 호출할 수 있습니다.
0: 완전 재진입 가능.
동시성이 허용되면 두 개의 동시 스레드가 동일한 프로세스에 속할 수 없습니다. 이는 잠재적인 경쟁 조건 시나리오를 찾을 때 염두에 두어야 할 사항입니다.
WDDM kmd 드라이버 진입점의 경우 사용자 영역에서 중요한 입력을 받는 꽤 많은 콜백(Exit, Render, Allocate, QueryAdapter)이 있습니다. 이를 찾기 전에 적절한 드라이버 초기화를 수행한 다음 콜백을 살펴봐야 합니다. 관련 구조 또는 인터페이스:
// Escape
NTSTATUS D3DKMTEscape(_In_ const D3DKMT_ESCAPE *pData );
typedef struct _D3DKMT_ESCAPE
{
D3DKMT_HANDLE hAdapter;
D3DKMT_HANDLE hDevice;
D3DKMT_ESCAPETYPE Type;
D3DDDI_ESCAPEFLAGS Flags;
VOID *pPrivateDriverData;
UINT PrivateDriverDataSize;
D3DKMT_HANDLE hContext;
} D3DKMT_ESCAPE;
// Render
NTSTATUS APIENTRY DxgkDdiRender(_In_ const HANDLE hContext, _Inout_ DXGKARG_RENDER *pRender){ ... }
typedef struct _DXGKARG_RENDER
{
const VOID CONST *pCommand;
const UINT CommandLength;
VOID *pDmaBuffer;
UINT DmaSize;
VOID *pDmaBufferPrivateData;
UINT DmaBufferPrivateDataSize;
DXGK_ALLOCATIONLIST *pAllocationList;
UINT AllocationListSize;
D3DDDI_PATCHLOCATIONLIST *pPatchLocationListIn;
UINT PatchLocationListInSize;
D3DDDI_PATCHLOCATIONLIST *pPatchLocationListOut;
UINT PatchLocationListOutSize;
UINT MultipassOffset;
UINT DmaBufferSegmentId;
PHYSICAL_ADDRESS DmaBufferPhysicalAddress;
} DXGKARG_RENDER;
// Allocation
NTSTATUS APIENTRY DxgkDdiCreateAllocation(const HANDLE hAdapter, DXGKARG_CREATEALLOCATION *pCreateAllocation){ ... }
typedef struct
_DXGKARG_CREATEALLOCATION
{
const VOID *pPrivateDriverData;
UINT PrivateDriverDataSize;
UINT NumAllocations;
DXGK_ALLOCATIONINFO *pAllocationInfo;
HANDLE hResource;
DXGK_CREATEALLOCATIONFLAGS Flags;
} DXGKARG_CREATEALLOCATION;
// queryadapter
NTSTATUS APIENTRY DxgkDdiQueryAdapterInfo(HANDLE hAdapter, DXGKARG_QUERYADAPTERINFO *pQueryAdapterInfo ){ ... }
typedef struct _DXGKARG_QUERYADAPTERINFO
{
DXGK_QUERYADAPTERINFOTYPE Type;
VOID *pInputData;
UINT InputDataSize;
VOID *pOutputData;
UINT OutputDataSize;
} DXGKARG_QUERYADAPTERINFO;16.3.2 Linux 그래픽 드라이버
Linux 그래픽 스택은 지난 몇 년 동안 많은 발전을 거쳤습니다. 이 섹션의 목적은 이 역사를 자세히 설명하고 수년에 걸쳐 이루어진 변경 사항에 대한 근거를 제공하는 것입니다. 오늘날 디자인은 여전히 이 역사에 깊이 뿌리를 두고 있으며, 이 섹션에서는 Linux 그래픽 스택의 현재 디자인을 더 잘 추진하기 위해 이 역사를 설명할 것입니다. 다음은 Linux 그래픽 드라이버 아키텍처와 관련된 각 모듈 또는 개념에 대한 간략한 설명입니다.
- PCI(Peripheral Component Interconnect): 사용자는 마더보드의 PCI 슬롯에 그래픽 카드를 삽입해야 합니다. PCI 사양은 대중에게 무료로 제공되지 않습니다. 이 컴퓨터 버스의 프로그래밍 진입점은 x86 아키텍처 I/O 포트 주소 공간의 0xCF8 및 0xCFC I/O 포트를 통해 액세스되는 PCI 구성 공간입니다. 보다 구체적으로 말하면 0xCF8은 주소 포트이고 0xCFC는 데이터 포트입니다. 각 PCI 엔터티(메모리의 바이트와 같이 버스에서 주소를 지정할 수 있는 가장 작은 단위)에는 고유한 구성 공간이 있습니다. 엔터티의 구성 공간에는 3가지 유형의 리소스가 있습니다.
입출력 메모리. 이는 엔터티가 디코딩하는 물리적 메모리 블록입니다. /proc/iomem의 내용을 확인하세요.
입력/출력 포트. 엔터티가 디코딩할 I/O 포트 공간의 데이터입니다. /proc/ioports 파일의 내용을 확인하세요.
IRQ(인터럽트 요청). /proc/irq 디렉토리의 내용을 확인하십시오.
이러한 리소스의 구성은 두 가지 시스템을 사용하여 수행됩니다.
PCI PNP(플러그 앤 플레이)는 더 이상 사용되지 않습니다.
현재 구현되는 ACPI(고급 구성 및 전원 인터페이스)는 OS(운영 체제) 커널에 의해 수행되는 작업입니다.
AGP(가속 그래픽 포트), PCI Express 카드: 시스템에서는 PCI 장치처럼 그래픽 카드가 AGP 슬롯 또는 PCI Express 슬롯에 연결된 것으로 표시됩니다.
ACPI(고급 구성 및 전원 인터페이스): 오늘날의 컴퓨터에는 ACPI 기능이 있는 경우가 많습니다. ACPI는 물리적 구성을 위해 PCI PNP를 대체하고 전원 관리, 다중 프로세서 기능 및 기타 기능을 추가합니다. PCI와 달리 ACPI 사양은 자유롭게 사용할 수 있습니다. ACPI는 메모리 테이블을 기반으로 합니다. 컴퓨터가 시작되면 운영 체제는 실제 메모리에서 RSDP(루트 시스템 설명 포인터)를 찾아야 합니다. x86 아키텍처에서는 "RSD PTR" 문자열을 특정 물리적 메모리 영역에서 찾아야 합니다.
**XORG, DDX(장치 종속 X) 및 DIX(장치 독립적) XORG에는 DMX(Distributed Multi-X) 서버, kdrive 서버 또는 유명한 XGL 서버와 같은 여러 서버가 있다는 점을 기억하십시오. DIX는 XORG의 일부이며 클라이언트 측, 네트워크 투명성 및 소프트웨어 렌더링을 처리합니다. DDX는 하드웨어(및 어느 정도 운영 체제)를 처리하는 XORG의 일부입니다.
EXA: EXA는 XORG로 가속화된 API이며 xfree86 DDX는 이를 구현하는 유일한 DDX입니다. EXA 가속(활성화된 경우)은 화면이 초기화될 때마다(예: 새 서버 생성 시작 시) 초기화됩니다.
DRI(직접 렌더링 인프라) 및 DRM(직접 렌더링 관리자): DRI 및 DRM은 주로 메사(즉, "libre" opengl 구현)에서 사용되는 그래픽 카드 하드웨어 프로그래밍을 위한 파이프라인이지만 하드웨어에 대한 액세스는 모든 그래픽 카드 하드웨어 클라이언트 간에 동기화되어야 하기 때문에 xfree86 DDX 비디오 드라이버 모듈은 클라이언트 자체이기 때문에 이를 처리해야 합니다. 그런 다음 EXA는 가속 작업을 수행하려고 할 때 DRI를 통해 하드웨어와 통신해야 합니다. xfree86 DDX 코드용 DRI xfree86 DDX 모듈이 있으며 DRI 방식을 통해 하드웨어 액세스를 원합니다. 이 모듈 및 관련 xfree86 DDX 코드는 DRM 사용자 수준 인터페이스 라이브러리 libdrm을 사용합니다. 이론적으로 미래의 DRM 발전을 통해 XORG 서버용 PCI 프로그래밍 코드에서 벗어날 수 있게 될 것입니다.


16.3.2.1 X11 인프라
X11 아키텍처 다이어그램은 DIX(장치 독립적 X), DDX(장치 종속 X), Xlib, 소켓, X 프로토콜, X 확장, 전송을 위한 shm->공유 메모리, XCB->비동기 등을 포함하여 다음과 같습니다.

X 서비스의 내부 상호 작용 다이어그램은 다음과 같습니다.

16.3.2.2 DRI/DRM 인프라
DRM(Direct Render Manager)은 최신 비디오 카드의 GPU와의 인터페이스를 담당하는 Linux 커널의 하위 시스템입니다. DRM은 사용자 공간 프로그램이 명령과 데이터를 GPU에 보내고 디스플레이 모드 설정 구성과 같은 작업을 수행하는 데 사용할 수 있는 API를 노출합니다. DRM은 원래 X Server 직접 렌더링 인프라의 핵심 공간 구성 요소로 개발되었지만 이후 Wayland와 같은 다른 그래픽 스택 대안에서 사용되었습니다.

DRM을 사용하면 충돌을 피하기 위해 여러 프로그램이 동시에 3D 비디오 카드에 액세스할 수 있습니다.

Linux 커널의 직접 렌더링 관리자를 사용하여 3D 가속 그래픽 카드 프로세스에 액세스합니다.

직접 렌더링 관리자 아키텍처 세부 정보: libdrm에 의해 인터페이스되는 DRM 코어 및 DRM 드라이버(GEM 및 KMS 포함).
처음에(Linux가 그래픽 하드웨어 가속을 처음 지원했을 때) 그래픽 카드에 직접 액세스하는 코드는 XFree86 서버 단 하나뿐이었습니다. 설계는 다음과 같습니다. 슈퍼유저 권한으로 실행함으로써 XFree86 서버는 사용자 공간에서 카드에 액세스할 수 있으며 2D 가속을 위한 커널 지원이 필요하지 않습니다. 이 설계의 장점은 단순성이며 XFree86 서버는 커널 구성 요소가 필요하지 않기 때문에 한 운영 체제에서 다른 운영 체제로 쉽게 이식될 수 있습니다. 수년 동안 이것은 가장 널리 퍼진 X 서버 설계였습니다(일부 드라이버의 커널에 모드 설정을 구현한 XSun과 같은 주목할만한 예외가 있었지만).
이후 최초의 하드웨어 독립적인 3D 가속 설계인 Utah-GLX가 Linux에 등장했습니다. Utah-GLX에는 기본적으로 GLX를 구현하고 2D 드라이버와 유사한 방식으로 사용자 공간에서 그래픽 하드웨어에 직접 액세스하는 추가 사용자 공간 3D 드라이버가 포함되어 있습니다. 3D 하드웨어가 2D와 명확하게 구분되는 시대에는(2D와 3D가 완전히 다른 기능을 사용하거나 3D 카드가 완전히 별도의 카드, 즉 3Dfx이기 때문에) 완전히 별도의 드라이버를 갖는 것이 합리적입니다. 또한 사용자 공간에서 하드웨어에 직접 액세스하는 것은 Linux에서 3D 가속을 달성하는 가장 쉽고 짧은 방법입니다.
동시에 프레임 버퍼 드라이버는 점점 더 널리 보급되었으며 동시에 그래픽 하드웨어에 직접 액세스할 수 있는 또 다른 구성 요소를 나타냈습니다. 프레임 버퍼와 XFree86 드라이버 사이의 잠재적인 충돌을 피하기 위해 VT 스위치에서 커널은 X 서버에 그래픽 하드웨어 상태를 저장하라는 신호를 보내기로 결정했습니다. 각 드라이버가 전체 GPU 상태를 VT 스위치에 저장하도록 요구하면 드라이버가 더욱 취약해지며, 갑자기 서로 다른 드라이버 간에 오류가 발생하기 쉬운 상호 작용에 직면하게 되는 개발자의 삶이 더욱 어려워집니다. XFree86 드라이버(xf86 비디오 vesa 및 기본 XFree86 드라이버)와 2개의 커널 프레임 버퍼 드라이버(vesafb 및 기본 프레임 버퍼 드라이버)에는 최소한 두 가지 가능성이 있으므로 GPU당 공존하는 드라이버의 조합이 최소한 4개 있다는 점을 명심하십시오.

분명히 이 모델에는 단점이 있습니다. 첫째, 승인되지 않은 사용자 공간 애플리케이션이 3D 그래픽 하드웨어에 액세스할 수 있도록 허용해야 합니다. 둘째, 위 이미지에서 볼 수 있듯이 모든 GL 가속은 X 프로토콜을 통해 간접적으로 수행되어야 하며 이로 인해 특히 텍스처 업로드와 같은 데이터 집약적인 기능의 경우 속도가 크게 느려집니다. Linux의 보안 및 성능 단점에 대한 우려가 커지면서 다른 모델이 필요합니다.
DRI 모델은 Utah-GLX 모델의 안정성과 보안 문제를 해결하기 위해 구성되었습니다. 이는 XFree86과 그 후속 제품인 X.Org에서 모두 사용됩니다. 이 모델은 보안 관점에서 3D 명령 흐름의 정확성을 확인하는 역할을 담당하는 추가 커널 구성 요소에 의존합니다. 이제 주요 변경 사항은 권한이 없는 OpenGL 응용 프로그램이 명령 버퍼를 커널에 제출하여 카드에 직접 액세스하는 대신 안전성을 확인한 다음 실행을 위해 하드웨어에 전달한다는 것입니다. 이 모델의 장점은 신뢰하는 사용자 공간이 더 이상 필요하지 않지만 XFree86의 2D 명령 흐름은 여전히 DRM을 거치지 않으므로 X 서버는 GPU 레지스터를 직접 매핑하려면 여전히 슈퍼유저 권한이 필요하다는 것입니다.

현재 스택은 새로운 요구 사항 세트에서 발전했습니다. 첫째, X 서버에 슈퍼유저 권한을 요구하는 것은 항상 심각한 보안 위험을 초래합니다. 둘째, 이전 설계에서는 서로 다른 드라이버가 단일 하드웨어에 영향을 미쳐 종종 문제를 일으켰습니다. 이 문제를 해결하기 위해서는 두 가지 핵심 측면이 있습니다. 첫째, 커널 프레임 버퍼 기능을 DRM 모듈에 병합하는 것과 둘째, X.Org가 DRM 모듈을 통해 그래픽 카드에 액세스하여 허가 없이 실행되도록 하는 것입니다. 이 모델을 KMS(커널 모드 설정)라고 하며, 이제 DRM 모듈이 프레임 버퍼 드라이버 역할을 담당하고 X.Org가 모드 설정 서비스를 제공합니다.

요약하자면, 애플리케이션은 그리기 호출을 캡슐화하는 특정 라이브러리를 통해 X.Org와 통신합니다. 현재 DRI 설계는 시간이 지남에 따라 여러 중요한 단계에서 발전해 왔습니다. 최신 스택에서는 모든 그래픽 하드웨어 활동이 커널 모듈 DRM에 의해 제어됩니다. Linux의 전체 모듈 상호 작용 다이어그램은 다음과 같습니다.

보다 자세한 상호 작용 및 계층화된 아키텍처는 다음과 같습니다.

16.3.2.3 프레임버퍼 드라이버
핵심적으로 프레임버퍼 드라이버는 다음 기능을 구현합니다.
모드 설정. 모드 설정에는 비디오 해상도 및 새로 고침 빈도 선택을 포함하여 화면에 사진을 표시하기 위한 비디오 모드 구성이 포함됩니다.
선택적인 2D 가속. 프레임 버퍼 드라이버는 비디오 메모리의 복사 및 엔터티 채우기를 포함하여 Linux 콘솔 가속화를 위한 기본 2D 가속을 제공할 수 있습니다. 때때로 후크를 통해 사용자 공간에 가속이 제공됩니다(그러면 사용자 공간은 루트 권한이 필요한 카드별 MMIO 레지스터를 프로그래밍해야 합니다).
이 두 부분만 구현함으로써 프레임 버퍼 드라이버는 Linux 그래픽 드라이버의 가장 단순하고 가장 적합한 형태로 남아 있습니다. 프레임 버퍼 드라이버가 항상 특정 카드 모델(예: Nvidia 또는 ATI)에 종속되는 것은 아닙니다. 드라이버는 그래픽 하드웨어에 직접 액세스하지 않지만 펌웨어 기능을 호출하여 모드 설정 및 2D 가속을 구현하는 vesa, EFI 또는 Openfirmware 위에 존재합니다.
프레임버퍼 드라이버는 가장 간단한 형태의 Linux 그래픽 드라이버입니다. 최소한의 구현 노력으로 프레임 버퍼 드라이버는 낮은 메모리 공간을 제공하므로 임베디드 장치에 유용합니다. 소프트웨어 폴백 기능이 존재하므로 가속 구현은 선택 사항입니다.
16.3.2.4 직접 렌더링 관리자
복잡한 세상에서는 커널 모듈을 사용하는 것이 필수입니다. 이 커널 모듈은 DRM(Direct Render Manager)이라고 하며 다양한 목적으로 사용될 수 있습니다.
펌웨어 업로드, DMA 영역 설정 등 그래픽 카드의 중요한 초기화를 커널에 배치합니다.
여러 사용자 공간 구성 요소 간에 렌더링 하드웨어를 공유하고 액세스를 처리합니다.
애플리케이션이 임의의 메모리 영역에서 DMA를 수행하는 것을 방지하고 더 일반적으로는 보안 취약성을 초래할 수 있는 방식으로 카드를 프로그래밍하는 것을 방지하여 보안을 강화합니다.
사용자 공간에 비디오 메모리 할당 기능을 제공하여 카드의 메모리를 관리합니다.
모드 설정이 가능하도록 DRM이 개선되어 DRM과 프레임버퍼 드라이버가 동일한 GPU를 놓고 경쟁하던 이전 상황이 단순화되었습니다. 대신 프레임버퍼 드라이버가 제거되고 DRM에 프레임버퍼 지원이 구현됩니다.
**커널 모듈(DRM)**은 전역 DRI/DRM 사용자 공간/커널 구성표입니다(아래 이미지에는 libdrm-DRM-entry-point-multiple 사용자 공간 애플리케이션이 포함되어 있음).

단순한 프레임 버퍼 지원 이상을 구현하기 위해 Linux 그래픽 드라이버를 설계할 때 최우선 순위는 DRM 구성 요소이며, 이는 효율적이면서 보안을 강화하는 설계를 이끌어내야 합니다. DRI/DRM 체계는 다양한 방식으로 구현될 수 있으며 인터페이스는 실제로 완전히 카드별로 다릅니다.
DRM 배치 버퍼 제출 모델: DRM 설계의 핵심에는 DRM_GEM_EXECBUFFER ioctl이 있습니다. 이를 통해 사용자 공간 응용 프로그램은 배치 버퍼를 커널에 제출한 다음 이를 GPU에 배치할 수 있습니다. 이 ioctl을 사용하면 하드웨어 공유, 메모리 관리, 메모리 보호 강화 등 다양한 작업을 수행할 수 있습니다.
DRM의 책임 중 하나는 여러 사용자 공간 프로세스에서 GPU 자체를 재사용하는 것입니다. GPU가 그래픽 상태를 유지하는 경우 여러 응용 프로그램이 동일한 GPU를 사용할 때 문제가 발생합니다. 응용 프로그램이 아무 작업도 수행하지 않으면 서로의 상태를 파괴합니다. 현재 하드웨어에 따르면 두 가지 주요 상황이 있습니다.
GPU에 하드웨어 상태 추적 기능이 있으면 하드웨어 공유가 더 간단해집니다. 각 애플리케이션을 별도의 컨텍스트로 보낼 수 있고 GPU가 각 애플리케이션 자체의 상태를 추적하기 때문입니다. 이 방법은 새 드라이버가 작동하는 방식입니다.
GPU에 여러 하드웨어 컨텍스트가 없는 경우 하드웨어를 재사용하는 일반적인 방법은 배치 버퍼에 대한 각 요청에 대해 상태를 다시 제출하는 것입니다. 이것이 Intel과 Radeon 드라이버가 GPU를 다중화하는 방식입니다. 상태를 다시 제출하는 책임은 전적으로 사용자 공간에 달려 있습니다. 사용자 공간이 각 배치 버퍼의 시작 부분에서 상태를 다시 제출하지 않으면 다른 DRM 프로세스의 상태가 해당 공간으로 유출됩니다. DRM은 또한 동일한 하드웨어에 대한 동시 액세스를 방지합니다.
커널은 메모리 부족 상황을 처리하기 위해 메모리 영역을 이동할 수 있습니다. 하드웨어에 따라 두 가지 구현 방법이 있습니다.
하드웨어에 완벽한 메모리 보호 및 가상화 기능이 있는 경우 메모리 리소스를 할당할 때 메모리 리소스를 GPU로 페이징하고 각 프로세스를 격리할 수 있습니다. 따라서 GPU 메모리의 메모리 보호를 지원하는 데 필요한 것은 많지 않습니다.
하드웨어에 메모리 보호 기능이 없더라도 커널에서 완전히 구현될 수 있으며 사용자 공간은 전혀 영향을 받지 않습니다. 재배치가 인식되지 않는 사용자 공간 프로세스에서 작동하도록 허용하기 위해 submit ioctl 명령은 모든 하드웨어 오프셋을 현재 위치로 대체하여 커널의 명령 버퍼를 다시 작성합니다. 이는 커널이 모든 메모리 버퍼의 현재 위치를 알고 있기 때문에 가능합니다. 임의의 GPU 메모리에 대한 액세스를 방지하기 위해 submit ioctl 명령은 이러한 각 오프셋이 호출 프로세스에 의해 소유되었는지 확인하고 그렇지 않은 경우 배치 버퍼를 거부할 수도 있습니다. 하드웨어가 이 기능을 제공하지 않을 때 이러한 방식으로 메모리 보호를 달성할 수 있습니다.
DRM은 최신 Linux 그래픽 스택의 모든 그래픽 활동을 관리하며 보안을 담당하는 스택에서 유일하게 신뢰할 수 있는 부분이므로 다른 구성 요소를 신뢰할 수 없습니다. 모드 설정, 프레임 버퍼 드라이버, 메모리 관리 등 기본적인 그래픽 기능을 제공합니다.
16.3.2.5 메사
Mesa3D 및 Mesa3D 그래픽 라이브러리로도 알려진 Mesa는 OpenGL, Vulkan 및 기타 그래픽 API 사양을 구현한 오픈 소스 소프트웨어입니다. Mesa는 이러한 사양을 공급업체별 그래픽 하드웨어 드라이버로 변환합니다. 가장 중요한 사용자는 두 가지 그래픽 드라이버입니다. 이 드라이버는 주로 Intel과 AMD가 해당 하드웨어에 대해 개발하고 자금을 지원합니다(AMD는 더 이상 사용되지 않는 AMD Catalyst에서 Mesa 드라이버 Radeon 및 RadeonSI를 홍보하고 Intel은 Mesa 드라이버만 지원합니다). Nvidia GeForce 드라이버 및 Catalyst와 같은 독점 그래픽 드라이버는 모든 Mesa를 자체 그래픽 API 구현으로 대체했으며 Nouveau라는 Mesa Nvidia 드라이버를 개발하려는 오픈 소스 노력은 주로 커뮤니티에서 개발되었습니다.
게임과 같은 3D 애플리케이션 외에도 최신 디스플레이 서비스(X.org의 Glamer 또는 Wayland의 Weston)도 OpenGL/EGL을 사용합니다. 따라서 모든 그래픽은 일반적으로 Mesa를 사용합니다. Mesa는 1993년 8월 Brian Paul이 시작한 프로젝트인 freedesktop에 의해 호스팅됩니다. Mesa는 이후 널리 채택되었으며 현재 OpenGL 사양을 관리하는 그래픽 하드웨어 제조업체인 Khronos 그룹을 포함하여 전 세계의 다양한 개인 및 회사의 수많은 기여를 포함하고 있습니다.
메사의 주요 용도는 두 가지입니다:
Mesa는 OpenGL의 소프트웨어 구현이며 참조 구현으로 간주됩니다. 이는 공식 OpenGL 적합성 테스트가 공개되지 않기 때문에 일관성을 확인할 때 유용합니다.
Mesa는 Linux에서 오픈 소스 그래픽 드라이버를 위한 OpenGL 진입점을 제공합니다.
Mesa는 Linux에서의 참조 OpenGL 구현이며 모든 오픈 소스 그래픽 드라이버는 3D용 Mesa를 사용합니다.

비디오 게임은 OpenGL을 통해 실시간으로 렌더링 계산을 GPU에 아웃소싱합니다. 셰이더는 OpenGL 셰이딩 언어 또는 SPIR-V를 사용하여 작성되고 CPU에서 컴파일됩니다. 컴파일된 프로그램은 GPU에서 실행됩니다. (아래 사진)

Linux 그래픽 스택은 아래 그림에 표시되어 있습니다: DRM 및 libDRM, Mesa 3D. 디스플레이 서비스는 윈도우 시스템에 속하며 게임과 같은 상위 계층 애플리케이션에만 사용됩니다.

Wayland의 무료 구현은 프레임 버퍼에 대한 액세스를 지원하기 위해 작성된 libwayland EGL이라는 특수 라이브러리인 EGL의 Mesa 구현에 의존하며 EGL 버전 1.5는 더 이상 사용되지 않습니다. GDC 2014에서 AMD는 내부 Blob 대신 DRM을 사용하는 전략 변경을 모색했습니다.

16.3.2.6 웨이랜드
Wayland는 X를 더 간단하게 대체하고 개발 및 유지 관리가 더 쉬운 것을 목표로 합니다. Wayland는 컴포지터가 클라이언트와 대화하기 위한 프로토콜이며 이 프로토콜의 C 라이브러리 구현입니다. 합성기는 독립형 디스플레이 서버, X 응용 프로그램 또는 Linux 커널 모드 설정 및 evdev 입력 장치에서 실행되는 wayland 클라이언트 자체일 수 있습니다. 클라이언트는 전통적인 애플리케이션, X 서버(루트 또는 전체 화면 없음) 또는 기타 디스플레이 서버일 수 있습니다. Wayland 프로젝트의 일부는 Wayland 합성기의 Weston 참조 구현이기도 합니다. Weston은 X 클라이언트 또는 Linux KMS로 실행될 수 있습니다. Weston 컴포지터는 많은 임베디드 및 모바일 사용 사례에 적합한 최소의 빠른 컴포지터입니다.

X(왼쪽)와 Wayland(오른쪽)를 사용한 드라이버 아키텍처 비교.
16.3.3 스케줄링 메커니즘
16.3.3.1 OS 및 GPU 추상화
10년 전, Microsoft와 대학의 연구원들은 운영 체제에서 GPU 추상화에 대한 운영 체제 지원 부족으로 인해 여러 응용 분야에서 GPU의 가용성이 근본적으로 제한된다는 GPU 추상화를 지원해야 한다고 지적했습니다. 운영 체제는 CPU, 입력 장치, 파일 시스템과 같은 가장 일반적인 리소스에 대한 추상화를 제공합니다. 대조적으로, 운영 체제는 현재 서투른 ioctl 인터페이스 뒤에 GPU를 숨겨서 추상화의 부담을 사용자 라이브러리와 런타임으로 옮기고 있습니다. 결과적으로 운영 체제는 공정성 및 격리와 같은 시스템 전반에 걸친 GPU 보장을 제공할 수 없으며 개발자는 GPU 및 기타 운영 체제 관리 리소스를 통합하는 시스템을 구축할 때 모듈성과 성능을 희생해야 합니다. 이들은 GPU 및 기타 가속기 장치를 일류 컴퓨팅 리소스로 지원하기 위한 새로운 커널 추상화를 제안합니다.

CPU 및 GPU 프로그램용 기술 스택. GPU 프로그램의 경우 운영 체제 수준과 CPU 프로그램의 사용자 모드 런타임 추상화 간에 일대일 대응이 없습니다.
GPU 추상화에 대한 직접적인 운영 체제 지원은 없으므로 이 워크로드에 GPU를 활용하려면 반드시 CUDA 또는 OpenCL과 같은 사용자 수준 GPU 프로그래밍 프레임워크 및 런타임이 필요합니다. 이러한 프레임워크에서 xform 및 감지를 구현하면 격리되어 실행되는 구성 요소의 속도가 크게 향상되지만 결합된 시스템(catusb | xform | 감지 | hidinput)은 사용자 커널 경계와 PCI-e 버스를 통한 하드웨어 간의 과도한 데이터 이동으로 인해 어려움을 겪게 됩니다.
최신 운영 체제는 현재 GPU 공정성과 성능 격리를 보장할 수 없습니다. 이는 주로 GPU가 공유 컴퓨팅 리소스(예: CPU)가 아니라 I/O 장치로 관리되고 해당 인터페이스가 알려진 작업(예: init_module, 읽기, 쓰기, ioctl)으로 제한되기 때문입니다. 이 디자인은 운영 체제가 해당 기능을 위해 GPU를 사용해야 하는 경우 심각한 제한이 됩니다. 실제로 NVIDIA GPU Direct는 이러한 기능을 구현하지만 관련된 모든 I/O 장치의 드라이버에 대한 전용 지원이 필요합니다. 직접 계산해 보세요(예: Windows 7에는 동일한 Aero 사용자 인터페이스가 있습니다). 현재 체제에서는 시간 분할 및 시간 초과를 통해 화면 새로 고침 빈도가 일정하게 유지되지만 운영 체제는 공정성과 시스템 로드 밸런싱을 적용할 때 GPU 드라이버에 크게 의존합니다.
새로운 아키텍처는 GPU 및 CPU 메모리 영역 전반에 걸쳐 데이터 관리의 상대적 어려움을 변화시킬 수 있지만, 소프트웨어는 계속해서 중요한 역할을 할 것이며 데이터 이동 최적화는 가까운 미래에도 여전히 중요할 것입니다. AMD의 Fusion은 CPU와 GPU를 단일 칩에 통합하지만 CPU와 GPU 메모리를 분할합니다. Intel의 Sandy Bridge(또 다른 CPU/GPU 조합)는 향후 몇 년 내에 다양한 형태의 통합 CPU/GPU 하드웨어가 출시될 것임을 보여줍니다. NVIDIA Optimus와 같은 새로운 하이브리드 시스템은 칩과 고성능 개별 그래픽 카드 모두에서 에너지 효율적이므로 CPU/GPU 칩을 결합한 경우에도 데이터를 더욱 명확하게 관리할 수 있습니다. 그러나 완전히 통합된 가상 메모리 시스템이라도 데이터 복사본을 최소화하려면 시스템 지원이 필요합니다.

프로토타입 시스템에서 CUDA 기반 xform 프로그램 구현의 상대적 GPU 실행 시간 및 오버헤드(낮을수록 좋음). sync는 동기 통신을 위해 CPU와 GPU 사이의 버퍼를 사용하고, async는 비동기 통신을 사용하며, async pp는 비동기 및 핑퐁 버퍼를 모두 사용하여 대기 시간을 더욱 숨깁니다. 막대 차트는 GPU의 실행 시간과 시스템 오버헤드로 구분됩니다. DtoH는 모든 프레임에서 장치와 호스트 간 통신 구현을 나타내며 그 반대도 마찬가지입니다. 둘 다 모든 프레임에서 양방향 통신을 나타냅니다. 보고된 실행 시간은 동기식, 양방향 경우(동기식 모두)와 관련됩니다.

CPU 집약적인 작업이 GPU 집약적인 작업에 미치는 영향. 현재 운영 체제 추상화는 시스템에 병렬 GPU 및 CPU 작업이 있을 때 성능 격리를 제공하는 운영 체제의 기능을 제한합니다. H→D는 호스트에서 GPU 장치로 통신하는 CUDA 워크로드인 반면, H←D는 GPU에서 호스트로 통신하고 H←D는 양방향 통신을 합니다.

지)
GPU 집약적 작업이 CPU 집약적 작업에 미치는 영향. 이 그래프는 프로그램이 GPU를 과도하게 사용하는 60초 동안 운영 체제가 마우스 이동 이벤트를 얼마나 자주(Hz 단위) 전달할 수 있는지 보여줍니다. 이 기간 동안 평균 CPU 사용률은 25% 미만이었습니다.
그들은 GPU를 더 넓은 범위의 애플리케이션 도메인에 적용할 수 있도록 다음과 같은 새로운 운영 체제 추상화를 제안합니다. 이러한 추상화를 통해 계산을 방향성 그래프로 표현할 수 있어 효율적인 데이터 이동과 효율적이고 공정한 일정 관리가 가능해집니다.
태스크. PTask는 기존 OS 프로세스 추상화와 유사하지만 PTask는 기본적으로 GPU에서 실행됩니다. PTask는 실행을 조정하기 위해 OS의 일부 조정이 필요하지만 사용자 모드 호스트 프로세스는 필요하지 않습니다. PTask에는 포트에 바인딩할 수 있는 입력 및 출력 리소스 목록이 있습니다(POSIX stdin, stdout, stderr 파일 설명자와 유사).
항구. 포트는 PTask 입력 및 출력 리소스에 바인딩될 수 있는 커널 네임스페이스의 개체입니다. 포트는 동적으로 바인딩되어야 하며 GPU 또는 CPU 메모리의 버퍼로 채워질 수 있는 GPU 코드의 데이터 및 매개 변수를 노출하는 방법을 제공하는 데이터 소스 또는 싱크입니다.
채널. 채널은 POSIX 파이프와 유사합니다. 포트를 다른 포트나 I/O 버스, 파일 등과 같은 시스템의 다른 데이터 소스 및 싱크에 연결합니다. 채널에는 GraphInputChannel, GraphOutChannel 및 GraphInternalChannel 하위 유형이 있습니다.
그래프. 그래프는 입력 및 출력 포트가 채널을 통해 연결되는 PTask 노드의 모음입니다. 여러 그래프를 독립적으로 생성하고 실행할 수 있으며 PTask 런타임은 그래프를 공정하게 예약하는 역할을 합니다.
운영 체제 인터페이스에서 이러한 새로운 추상화를 지원하려면 ptask, 포트 및 채널을 생성하고 관리하기 위한 새로운 시스템 호출이 필요합니다. 추가 시스템 호출은 POSIX의 프로세스 API, 프로세스 간 통신 API 및 스케줄러 힌트 API와 유사합니다.
GPU를 사용하여 운영 체제 스케줄링을 조정하면 두 가지 주요 이점이 있습니다.
효율성. 이는 GPU에서 ptask가 준비되고 예약되는 사이의 대기 시간이 짧을 뿐만 아니라 컴퓨팅 대역폭을 완전히 활용하기 위해 GPU에서 충분한 ptask 작업을 예약하는 것을 의미합니다.
**공정성.**는 GPU 활용도와 사용자 인터페이스 응답성 간의 운영 체제 스케줄러 균형을 나타냅니다. 또한 GPU와 경쟁하는 PTAK는 모두 컴퓨팅 대역폭의 공정한 분배를 받습니다. 일반적인 CUDA 프로그램은 짧은 지연 시간 예약에 신경 쓰지 않기 때문에 모든 PTASK에 이러한 예약 요구 사항이 모두 있는 것은 아닙니다.
요약하자면, 그들은 대화형, 대규모 병렬 장치를 관리하기 위해 커널 추상화의 근본적인 재구성을 옹호합니다. 커널은 프로그래머가 우수한 성능과 짧은 대기 시간을 달성하는 데 필요한 만큼의 하드웨어 세부 정보만 노출하는 동시에 머신 토폴로지를 기반으로 캡슐화되고 전문화된 통신 추상화를 제공해야 합니다. GPU는 공정성과 격리를 제공하기 위해 운영 체제에서 관리해야 하는 범용 공유 컴퓨팅 리소스입니다.
16.3.3.2 할로겐화물 파이프라인
GPU에서 Halide 파이프라인을 위한 일정 합성은 Halide DSL과 컴파일러가 알고리즘 설명과 최적화된 일정을 분리하여 이기종 아키텍처에 대한 이미지 처리 파이프라인을 위한 고성능 코드 생성을 가능하게 함을 보여줍니다. 그러나 자동 일정 생성은 현재 멀티 코어 CPU 아키텍처에서만 작동합니다. 따라서 GPU 지원 플랫폼에 최적화할 때는 여전히 전문가 수준의 지식이 필요합니다. 그들은 CUDA 기반 GPU 아키텍처에 대한 일정을 효율적으로 생성하기 위해 새로운 최적화 프로세스로 현재 Halide 자동 스케줄러를 확장했습니다. 실험 결과, 스케줄링은 수동 스케줄링에 비해 평균 10% 빠르고, 기존 자동 스케줄링에 비해 2배 이상 빠른 것으로 나타났다.

일반 파이프라인 예: 파이프라인을 최적화 계획이 할당된 더 작은 단계 그룹으로 분할하기 전에 공통 단계를 소비자에 인라인합니다.

간단한 구현에서는 서로 다른 CUDA 코어의 각 단계를 완전히 계산하고 모든 데이터를 전역 메모리에 저장합니다.

겹치는 타일 일정은 하나의 타일 내 반복(또는 스레드 블록)에 필요한 모든 픽셀을 계산하여 공유 메모리에 저장합니다.
또한 이 문서에서는 CUDA 기반 GPU 아키텍처에 최적화된 일정을 생성하기 위해 Halide 마스터 자동 스케줄러에 구현된 새로운 최적화 프로세스를 소개합니다. 이는 사소한(점별 소비) 단계가 먼저 소비자에 인라인된 다음 Halide 마스터에 구현된 그리디 알고리즘을 사용하여 그룹화되는 현재 최적화 파이프라인과 유사한 프로세스를 따릅니다. 아래 이미지는 자동 스케줄러에서 사용되는 최적화 흐름의 개요를 보여줍니다.

기본 스케줄링 프로세스: 스케줄러에는 주어진 파이프라인에 대해 최적화된 스케줄을 생성하기 위해 주기 경계 추정치와 사용자가 제공한 목표 사양 설명이 필요합니다. 컴파일 흐름의 대부분의 단계는 자동 GPU 스케줄링을 지원하도록 확장되었습니다.
16.3.3.3 하드웨어 가속 GPU 스케줄링
하드웨어 가속 GPU 스케줄링에서는 2020년 5월 WDDM에서 도입된 하드웨어 가속 GPU 스케줄링 메커니즘을 설명합니다.
WDDM(Windows Display Driver Model 1.0)이 출시되고 Windows에 GPU 스케줄링이 도입된 지 거의 14년이 지났습니다. 애플리케이션이 원하는 작업을 GPU에 제출했던 WDDM 이전 시절을 기억하는 사람은 거의 없습니다. 이는 엄격한 "먼저 제출, 가장 먼저 실행" 방식으로 실행되는 글로벌 큐에 제출됩니다. 대부분의 GPU 응용 프로그램이 전체 화면 게임이었던 당시에는 이러한 가장 기본적인 일정 계획이 한 번에 하나씩 실행되는 것이 가능했습니다.
보다 풍부한 그래픽과 애니메이션을 위해 GPU를 사용하는 광범위한 애플리케이션으로 전환함에 따라 플랫폼은 응답성이 뛰어난 사용자 경험을 보장하기 위해 GPU 작업의 우선 순위를 더 잘 지정해야 합니다. 그리하여 WDDM GPU 스케줄러가 탄생했습니다.
시간이 지남에 따라 Windows는 WDDM 코어의 GPU 스케줄러를 크게 향상시켜 각각의 새로운 WDDM 버전에서 추가 기능과 시나리오를 지원했습니다. 그러나 진화 과정에서 스케줄러의 한 측면은 변경되지 않았습니다. 다양한 응용 프로그램에서 제출한 작업을 조정하고 우선 순위를 지정하고 예약하는 일을 담당하는 우선 순위가 높은 스레드를 CPU에서 계속 실행합니다.
GPU를 예약하는 이 방법에는 제출 오버헤드와 GPU에 도착하는 작업의 대기 시간 측면에서 몇 가지 근본적인 제한이 있으며, 이는 대부분 전통적인 애플리케이션 작성 방법으로 가려집니다. 예를 들어 애플리케이션은 일반적으로 프레임 N에서 GPU 작업을 수행하고 프레임 N+1에 대한 GPU 명령을 준비하기 위해 CPU가 먼저 실행되도록 합니다. 이러한 GPU 명령 일괄 버퍼링을 통해 애플리케이션은 프레임당 몇 번만 제출할 수 있으므로 예약 비용이 최소화되고 우수한 CPU-GPU 실행 병렬성이 보장됩니다.
CPU와 GPU 간의 버퍼링에 따른 본질적인 부작용은 사용자가 경험하는 대기 시간이 증가한다는 것입니다. CPU가 "프레임 N+1" 동안 사용자 입력을 선택하지만 GPU가 다음 프레임까지 사용자 입력을 렌더링하지 않는 것과 대기 시간 감소 및 제출/스케줄링 오버헤드 사이에는 근본적인 긴장이 있습니다. 애플리케이션은 대기 시간을 줄이기 위해 더 자주 작은 배치로 제출하거나 더 큰 배치로 작업을 제출하여 제출 및 예약 오버헤드를 줄일 수 있습니다.
Windows 10 2020년 5월 업데이트에서는 사용자 선택에 따라 새로운 GPU 스케줄러가 도입되지만 기본적으로 꺼져 옵션이 있습니다. 적절한 하드웨어와 드라이버를 사용하면 Windows는 이제 GPU 스케줄링의 상당 부분을 전용 GPU 기반 스케줄링 프로세서로 오프로드할 수 있습니다. Windows 시스템은 Windows 설정 -> 시스템 -> 디스플레이 -> 그래픽 설정을 통해 설정 페이지에 액세스하여 하드웨어 가속 GPU 스케줄링을 켜거나 끌 수 있습니다.

Windows는 계속해서 우선 순위를 제어하고 컨텍스트 내에서 어떤 응용 프로그램이 우선 순위를 갖는지 결정합니다. 고주파수 작업을 GPU 스케줄링 프로세서로 오프로드하고 다양한 GPU 엔진의 양자 관리 및 컨텍스트 전환을 처리합니다. 새로운 GPU 스케줄러는 드라이버 모델에 대한 중요하고 근본적인 변화입니다. 스케줄러를 변경하는 것은 집에 살면서 집의 기초를 다시 세우는 것과 비슷합니다.
새로운 스케줄러는 GPU 스케줄링의 오버헤드를 줄이지만 대부분의 애플리케이션은 버퍼링을 통해 스케줄링 비용을 숨기도록 설계되었습니다. 하드웨어 가속 GPU 스케줄링의 첫 번째 단계의 목표는 그래픽 하위 시스템의 기본 기둥을 현대화하고 향후에 대비하는 것입니다.
현재 일부 리뷰 기사에서는 이 기능을 켜도 일부 3A 게임의 프레임 속도가 실제로 향상되지 않는 것으로 나타났습니다.
16.3.3.4 타임그래프
GPU는 이제 그래픽 및 데이터 병렬 컴퓨팅에 일반적으로 사용됩니다. 여러 작업이 동시에 GPU에 액세스하는 멀티태스킹 환경에서 점점 더 많은 애플리케이션이 GPU에서 가속되는 경향이 있으므로 운영 체제는 특히 실시간 설정에서 GPU 리소스 관리에 우선 순위 지정 및 격리 기능을 제공해야 합니다. 현재 주류 GPU는 명령 기반입니다.

멀티태스킹의 일반적인 문제는 CPU로 인해 GPU가 차단되는 경우가 많다는 것입니다.

TimeGraph: 실시간 멀티태스킹 환경을 위한 GPU 스케줄링은 중요한 GPU 워크로드를 성능 간섭으로부터 보호하도록 설계된 장치 드라이버 수준의 실시간 GPU 스케줄러인 TimeGraph를 도입합니다.
TimeGraph는 GPU와 CPU를 동기화하여 사용자 공간에서 발행된 GPU 명령을 모니터링하고 응답 방식으로 GPU 리소스 사용을 제어하는 새로운 이벤트 중심 모델을 채택합니다. TimeGraph는 GPU 처리의 비동기 및 비선점 특성으로 인해 발생하는 응답 시간과 처리량 간의 균형을 해결하기 위해 두 가지 우선 순위 기반 스케줄링 전략을 지원합니다. 리소스 예약 메커니즘은 GPU 리소스 사용량을 계산하고 적용하는 데에도 사용되므로 오작동하는 작업으로 인해 GPU 리소스가 소진되는 것을 방지합니다. 또한 격리를 강화하기 위해 GPU 명령 실행 비용에 대한 예측을 제공합니다.
OpenGL 그래픽 벤치마크를 사용한 실험에서는 TimeGraph가 극한의 GPU 작업 부하에도 불구하고 주요 GPU 작업에 대해 원하는 수준으로 프레임 속도를 유지할 수 있는 반면, TimeGraph 지원이 없으면 이러한 작업은 거의 응답하지 않는 것으로 나타났습니다. 또한, 시간 그래프에 부과되는 성능 오버헤드는 4~10%로 제한할 수 있으며, 이벤트 중심 스케줄러의 처리량은 기존 틱 중심 스케줄러에 비해 약 30배 더 높은 것으로 나타났다.
이 기사에서는 시스템이 범용 멀티 코어 CPU와 온보드 GPU로 구성되어 있고 GPU 내부 장치를 조작하지 않으므로 GPU 명령이 GPU에 제출된 후 선점되지 않는다고 가정합니다. TimeGraph는 라이브러리, 컴파일러 및 런타임 엔진과 독립적이므로 TimeGraph의 원리는 다양한 GPU 아키텍처(예: NVIDIA Fermi/Tesla 및 ATI Stream)와 프로그래밍 프레임워크(예: OpenGL, OpenCL, CUDA 및 HMPP)에 적용 가능합니다. 현재 TimeGraph는 Gallium3D OpenGL 소프트웨어 스택의 Nouveau용으로 설계 및 구현되었으며 OpenCL도 지원할 계획입니다. 또한 TimeGraph는 CUDA 및 HMPP를 지원하는 PathScale ENZO 제품군에 패키지된 PSCNV 오픈 소스 드라이버로 포팅되었습니다. 그러나 이 기사에서는 현재 사용 가능한 오픈 소스 솔루션인 Nouveau 및 Gallium3D를 고려하여 OpenGL 워크로드에 중점을 둡니다.
TimeGraph는 장치 드라이버의 일부이며 사용자 공간 프로그램이 GPU 명령을 GPU에 제출하는 인터페이스입니다. 장치 드라이버는 대부분의 UNIX 계열 운영 체제에서 X Window System의 일부로 사용되는 DRI(Direct Rendering Infrastructure) 모델을 기반으로 설계되었다고 가정합니다. DRI 모드에서 사용자 공간 프로그램은 GPU에 직접 액세스하여 윈도우 프로토콜을 사용하지 않고 프레임을 렌더링하는 동시에 윈도우 서버를 사용하여 렌더링된 프레임을 화면에 블릿할 수 있습니다. GPGPU 프레임워크에는 이러한 창 절차가 필요하지 않으므로 해당 모델이 더 단순화됩니다.
GPU 명령을 GPU에 제출하려면 사용자 공간 프로그램에 GPU 채널이 할당되어야 하며, 이는 개념적으로 GPU의 별도 주소 공간을 나타냅니다. 예를 들어 NVIDIA Fermi 및 Tesla 아키텍처는 128개 채널을 지원하며 각 채널에 대한 GPU 명령 제출 모델은 아래 그림에 나와 있습니다.

GPU 명령은 모델을 제출합니다.
각 채널은 사용자 푸시 버퍼와 커널 푸시 버퍼라는 두 가지 유형의 커널 공간 버퍼를 사용합니다. 사용자 푸시 버퍼는 GPU 명령이 사용자 공간에서 푸시되는 해당 작업의 주소 공간에 매핑됩니다. GPU 명령은 일반적으로 사용자 공간 원자성 가정과 일치하도록 비선점형 영역으로 그룹화됩니다. 한편, 커널 푸시 버퍼는 호스트 장치 동기화, GPU 초기화, GPU 모드 설정 등 커널 프리미티브에 사용됩니다.
사용자 공간 프로그램이 GPU 명령을 사용자 푸시 버퍼에 푸시할 때, 간접 버퍼라고 하는 커널 푸시 버퍼의 특정 링 버퍼 부분에도 패킷을 씁니다. 여기서 각 패킷은 특정 GPU 명령 그룹을 찾는 (크기 및 주소) 튜플입니다. 드라이버는 명령 제출에 사용되는 버퍼를 읽도록 GPU의 명령 전달 장치를 구성합니다. 이 링 버퍼는 동일한 위치에서 시작하는 GET 및 PUT 포인터에 의해 제어됩니다. 패킷이 버퍼에 기록될 때마다 드라이버는 PUT 포인터를 패킷 끝으로 이동하고 GPU 명령 발송 장치에 신호를 보내 GET 포인터와 PUT 포인터 사이에 있는 패킷이 포함된 GPU 명령 그룹을 다운로드합니다. 그러면 GET 포인터가 PUT 포인터와 동일한 위치로 자동 업데이트됩니다. 이러한 GPU 명령 그룹이 GPU에 제출되면 드라이버는 더 이상 이를 관리하지 않고 다음 GPU 명령 그룹(있는 경우)을 계속 제출합니다. 따라서 이 간접 버퍼는 명령 대기열 역할을 합니다.
각 GPU 명령 그룹에는 여러 GPU 명령이 포함될 수 있습니다. 각 GPU 명령은 헤더(헤더)와 데이터로 구성됩니다. 헤더에는 메서드와 데이터 크기가 포함되고, 데이터에는 메서드에 전달된 값이 포함됩니다. 메서드는 GPU 명령을 나타내며, 그 중 일부는 컴퓨팅과 그래픽 간에 공유되고 다른 일부는 각각에 고유합니다. GPU로 오프로드된 후에는 장치 드라이버가 GPU 명령 세트를 선점하지 않는다고 가정합니다. 동일한 GPU 채널에서 GPU 명령이 잘못된 순서로 실행됩니다. GPU 채널은 GPU 엔진에 의해 자동으로 전환됩니다.
위의 드라이버 모델은 특히 NVIDIA Fermi 및 Tesla 아키텍처를 대상으로 하는 DRM(Direct Render Manager)을 기반으로 하지만 약간의 수정을 통해 다른 아키텍처에서도 사용할 수 있습니다.
TimeGraph의 아키텍처와 나머지 소프트웨어 스택과의 상호 작용은 아래 그림에 나와 있습니다. 사용자 공간 프로그램은 수정할 필요가 없으며, 기존 소프트웨어 프레임워크를 통해 GPU 명령 그룹을 생성할 수 있습니다. 그러나 TimeGraph는 PushBuf라는 장치 드라이버 공간의 특정 인터페이스와 통신해야 합니다. 이를 통해 사용자 공간은 사용자 푸시 버퍼에 저장된 GPU 명령 그룹을 제출할 수 있습니다. TimeGraph는 이 PushBuf 인터페이스를 사용하여 GPU 명령 그룹을 대기열에 추가합니다. 또한 GPU에서 CPU로의 인터럽트를 위해 준비된 IRQ 핸들러를 사용하여 다음으로 사용 가능한 GPU 명령 그룹을 예약합니다.

TimeGraph는 GPU 명령 스케줄러, GPU 예약 관리자 및 GPU 명령 프로파일러로 구성됩니다. GPU 명령 스케줄러는 작업 우선순위에 따라 GPU 명령 그룹을 대기열에 추가하고 예약합니다. 또한 GPU 예약 관리자와 협력하여 작업에 대한 GPU 실행 시간을 계산하고 적용합니다. GPU 명령 프로파일러는 예약 범위 초과를 방지하기 위해 GPU 명령 실행 비용 예측을 지원합니다. 응답 시간과 처리량 간의 균형을 해결하기 위해 두 가지 예약 전략이 지원됩니다.
- 예측 가능한 응답 시간(PRT): 이 정책은 GPU의 우선 순위 반전을 최소화하여 우선 순위에 따라 예측 가능한 응답 시간을 제공합니다. GPU가 유휴 상태가 아니면 GPU 명령이 대기열에 추가됩니다. GPU가 유휴 상태이면 GPU 명령이 예약됩니다.

- 높은 처리량(HT): 이 정책은 전체 처리량을 증가시켜 추가적인 우선순위 반전을 허용합니다. GPU가 유휴 상태가 아닌 경우 우선 순위가 현재 GPU 컨텍스트보다 낮은 경우에만 GPU 명령이 대기열에 추가됩니다. GPU가 유휴 상태이면 GPU 명령이 예약됩니다.

ng)
또한 격리와 처리량 간의 균형을 해결하기 위해 두 가지 GPU 예약 전략을 지원합니다.
- 사후 적용(PE): 이 정책은 처리량을 희생하지 않고 GPU 명령 그룹이 완료된 후 GPU 리소스 사용을 강제합니다. GPU 리소스 사용량을 최적화하고 각 작업(/proc/GPU/$task)의 용량(C) 및 기간(P)을 지정합니다.

- AE(선험적 적용): 이 정책은 GPU 실행 비용 예측을 사용하여 GPU 명령 그룹을 제출하기 전에 GPU 리소스 사용을 강제하지만 추가 오버헤드를 추가합니다. 각 작업(/proc/GPU/$task)의 용량(C) 및 기간(P)을 지정합니다.

여러 작업을 단일 보존으로 통합하기 위해 TimeGraph 보존 메커니즘은 공유 보존 모드를 제공합니다. 특히 TimeGraph는 로드 시 PE 정책을 사용하여 특별한 공유 예약 인스턴스(특정 예약에 속하지 않는 모든 GPUAccessed 작업을 제공하는 Background라고 함)를 생성합니다. 아래 그림은 PushBuf 인터페이스와 IRQ 핸들러의 상위 레벨 다이어그램을 보여주며, TimeGraph에 의해 도입된 수정 사항은 굵은 프레임으로 강조 표시되어 있습니다. 이 다이어그램은 Nouveau 구현을 기반으로 하지만 대부분의 GPU 드라이버에는 유사한 제어 흐름이 있어야 합니다.

PushBuf 인터페이스와 IRQ 핸들러 및 시간 그래프 체계의 관계 다이어그램.
GPU 명령 스케줄러의 목표는 작업 우선순위에 따라 GPU 명령의 비선점형 그룹을 대기열에 추가하고 예약하는 것입니다. 이를 위해 TimeGraph에는 일시 중지된 작업에 대한 대기 대기열이 포함되어 있으며 현재 GPU에서 실행 중인 GPU 명령 그룹에 대한 포인터 목록인 GPU 온라인 목록도 관리합니다.
GPU 명령 그룹이 PushBuf 인터페이스에 진입하면 GPU 온라인 목록을 사용하여 현재 실행 중인 GPU 명령 그룹이 있는지 확인합니다. 목록이 비어 있으면 해당 작업이 목록에 삽입되고 GPU 명령 그룹이 GPU에 제출됩니다. 그렇지 않으면 작업이 예약 대기 대기열에 삽입됩니다.
GPU 온라인 목록을 관리하려면 GPU 명령 그룹이 완료된 시점에 대한 정보가 필요합니다. TimeGraph는 이전 작업에서 채택한 틱 중심 모델이 아닌 GPU-CPU 인터럽트를 사용하여 각 GPU 명령 그룹의 완료를 알리는 이벤트 중심 모델을 채택합니다. 각 인터럽트에서 해당 GPU 명령 그룹이 GPU 온라인 목록에서 제거됩니다.
TimeGraph는 두 가지 GPU 스케줄링 전략을 지원합니다. PRT(예측 가능한 응답 시간) 정책은 중요한 작업에 영향을 주지 않고 이러한 작업이 적시에 실행되도록 권장합니다. 이 정책은 GPU 명령 그룹이 작업 우선순위에 따라 예약되어 우선순위가 높은 작업이 GPU에서 응답한다는 점에서 예측 가능합니다. 반면, HT(High Throughput) 전략은 최대한 빨리 실행해야 하는 작업에 적합합니다. PRT 정책은 처리량을 희생하여 작업이 중단되는 것을 방지하는 반면, HT 정책은 한 작업에 대해 높은 처리량을 달성하지만 다른 작업을 차단할 수 있다는 점에서 절충점이 있습니다. 예를 들어 데스크톱 위젯, 브라우저 플러그인 및 비디오 플레이어 작업에는 PRT 전략을 사용해야 하고, 3D 게임 및 대화형 3D 인터페이스 작업에는 HT 전략을 사용할 수 있습니다.
PRT 정책은 모든 GPU 명령 그룹이 이전 GPU 명령 그룹(있는 경우)이 완료될 때까지 기다리도록 합니다. 특히, GPU 온라인 목록이 비어 있으면 장치 드라이버에 도착하는 새로운 GPU 명령 그룹이 즉시 GPU에 제출될 수 있습니다. 그렇지 않으면 해당 작업이 대기 대기열에서 대기해야 합니다. 대기 큐(있는 경우)에서 우선 순위가 가장 높은 작업은 GPU의 모든 인터럽트에서 깨어납니다.
아래 그림 (a)는 우선 순위가 다른 세 가지 작업, 즉 높은 우선 순위, 중간 우선 순위(MP) 및 낮은 우선 순위(LP)가 PRT 정책에 따라 GPU에 예약되는 방식을 보여줍니다. MP 작업이 도착하면 실행 중인 GPU 명령 그룹이 없기 때문에 해당 GPU 명령 그룹이 GPU에서 실행될 수 있습니다. GPU와 CPU가 비동기적으로 실행되는 경우 마지막 GPU 명령 그룹이 실행되는 동안 MP 작업이 다시 도착할 수 있습니다. 그러나 PRT 정책에 따르면 GPU가 유휴 상태가 아니므로 이번에는 MP 작업이 대기열에 추가됩니다. 같은 이유로 더 높은 우선순위의 작업이 곧 도착할 수 있으므로 다음 HP 작업도 대기열에 추가됩니다. TimeGraph가 각 GPU 명령 그룹 끝에 추가하는 특정 GPU 명령 세트는 CPU에 대한 인터럽트를 생성하고 이에 따라 TimeGraph 스케줄러를 호출하여 대기 대기열에서 우선 순위가 가장 높은 작업을 깨웁니다. 따라서 다음으로 MP 작업 대신 GPU에서 HP 작업을 수행하도록 선택합니다. 이런 방식으로 LP 작업의 다음 인스턴스와 HP 작업의 두 번째 인스턴스가 우선 순위에 따라 예약됩니다.
GPU 명령 그룹의 도착 시간을 알 수 없고 각 GPU 명령 그룹이 비선점적이라는 점을 고려할 때 PRT 전략은 예측 가능한 응답 시간을 제공하는 가장 좋은 방법이라고 믿습니다. 그러나 각 GPU 명령 그룹 경계에서 스케줄링 결정을 내리면 아래 그림 (a)와 같이 필연적으로 오버헤드가 발생합니다.
HT 정책은 이러한 예약 오버헤드를 줄여 예측 가능한 응답 시간을 약간 줄입니다. (i) 현재 실행 중인 GPU 명령 그룹이 동일한 작업에 의해 제출되었고 (ii) 대기 대기열에 더 높은 우선 순위의 작업이 없는 경우 GPU 명령 그룹을 GPU에 즉시 제출하는 것이 허용됩니다. 그렇지 않으면 PRT 정책과 동일한 방식으로 일시 중단되어야 합니다. 인터럽트 중에 대기 대기열에서 우선순위가 가장 높은 작업은 GPU 온라인 목록이 비어 있을 때만(GPU 유휴) 깨어납니다.
아래 그림 (b)는 아래 그림 (a)에 사용된 동일한 GPU 명령 그룹 세트가 HT 정책에 따라 예약되는 방식을 보여줍니다. PRT 정책과 달리 MP 작업의 두 번째 인스턴스는 현재 실행 중인 GPU 명령 그룹이 자체적으로 실행되었기 때문에 GPU 명령 그룹을 즉시 제출할 수 있습니다. MP 작업의 두 GPU 명령 그룹은 HP 작업의 두 GPU 명령 그룹과 마찬가지로 유휴 시간을 생성하지 않고 지속적으로 실행될 수 있습니다. 따라서 HT 전략은 처리량 중심 작업에 더 적합하지만 HP 작업은 MP 작업에 의해 더 오랫동안 차단됩니다. 이는 절충안이며 우선순위 반전이 중요한 경우 PRT 전략이 더 적합합니다.

TimeGraph의 GPU 스케줄링 예.
TimeGraph는 기록 기반 접근 방식을 사용하여 GPU 실행 시간 예측을 지원합니다. 즉, 들어오는 GPU 명령 시퀀스와 일치하는 이전 GPU 명령 시퀀스의 레코드를 검색하며 2D에 적합하지만 3D 조사 및 계산이 필요합니다.
TimeGraph를 켠 후 다양한 측면에서 성능에 미치는 영향은 다음과 같습니다.

3D 게임 프레임 속도는 백그라운드에서 그래픽 폭탄과 경쟁합니다.

간섭 시간.

독립형 장치 성능.
요약하면 TimeGraph는 멀티 태스킹 환경에서 GPU 애플리케이션의 우선 순위 지정 및 격리를 지원합니다.
장치 드라이버 솔루션: 사용자 공간을 수정하지 않습니다.
GPU 명령 스케줄링.
GPU 리소스 사용량을 예약합니다.
16.3.3.5 GPU 스케줄링
여러 독립 애플리케이션 간에 단일 GPU를 공유하는 것의 의미와 어려움을 이해하려면 먼저 GPU가 일반적으로 단일 애플리케이션에 대한 작업 예약을 처리하는 방법을 이해해야 합니다. 일정은 시간과 공간 차원에 걸쳐 고려됩니다. 즉, 작업을 언제 어디서 실행해야 하는지 결정합니다. 시간 스케줄링은 위에서 설명한 FCFS 알고리즘에 의해 결정됩니다. 작업이 대기열의 헤드에 도달하면 서비스가 제공됩니다(사용 가능한 리소스가 충분한 경우). 이 스케줄링은 또한 비선점적입니다. 블록이 장치에 스케줄되면 다른 블록에 대한 실행을 선점할 수 없습니다. 또한 이 비선점은 작업 수준에도 적용됩니다. 공간 스케줄링은 작업 리소스 요구 사항과 SMX의 리소스 가용성에 대한 이중 고려 사항을 기반으로 작업을 실행할 수 있는 SMX 장치를 결정합니다.
하드웨어 스케줄링 수준에서 스케줄링 가능한 가장 작은 단위는 스레드 블록입니다. 즉, 장치의 일부 SMX가 실행을 위해 디스패치하려면 전체 블록의 리소스 요구 사항을 충족할 수 있어야 합니다. 또한 코어의 모든 스레드 블록을 한 번에 처리할 필요가 없으므로 실행 웨이브 개념이 도입됩니다. 블록 스케줄링을 즉각적인 프로세스로 고려하면 각 웨이브는 블록 수요 및 장치 리소스 가용성을 기반으로 허용되는 최대 블록 수를 스케줄링합니다. 웨이브가 예약되면 나머지 블록은 장치의 다른 실행이 완료될 때까지 실행 대기열에 남아 있으므로 리소스가 확보됩니다.
완전한 실행 웨이브를 구성하는 블록 수를 결정하는 많은 요소가 있습니다. 커널 스레드 블록의 구성은 필요한 각 리소스의 양을 결정하므로 중요한 요소입니다. 또 다른 주요 제한 요소는 SMX당 허용되는 상주 스레드 블록 수에 대한 기본 제한 사항입니다. 상주 블록의 최대 수에 도달하기 전에 다른 리소스가 완전히 소진되지 않는 경우가 종종 있기 때문에 이 제약 조건에 유의해야 합니다. 이는 특히 구성 및 리소스 요구 사항이 다른 코어로 구성된 동시 실행 시나리오에서 가능합니다. 다음 표에는 여러 세대의 NVIDIA GPU에서 각 SMX에 대한 리소스 제한이 나열되어 있습니다.
컴퓨팅 능력 3.5 5.2 6.0 7.0
최대 스레드/SMX 2048년 2048년 2048년 2048년
최대 스레드 블록/SMX 16 32 32 32
블록당 최대 스레드 1024 1024 1024 1024
최대 레지스터/SMX 65536 65536 65536 65536
SMX당 공유 메모리 48KB 96KB 64KB 96KB
첫째, 모든 SMX 장치에 스레드 블록을 배포하면 파워 게이팅과 같은 특정 기술을 안정적으로 적용하여 전력 효율성을 향상시킬 수 없습니다. 둘째, 공간 스케줄링 방법은 비결정적 패턴으로 이어져 특정 블록을 특정 SMX에 매핑하여 활용도 및/또는 효율성을 향상시킬 수 있는 방법을 제거합니다. 마지막으로, 동시 시나리오에서는 독립 코어의 다양한 리소스 요구 사항으로 인해 SMX 장치 세트가 비대칭적으로 활용됩니다.
여러 독립 애플리케이션이 GPU 장치를 공유하는 시나리오에 위의 스케줄링 전략을 적용하려면 리소스 충돌을 제거하고 공정성과 같은 특정 속성을 보장해야 합니다. GPU 컴퓨팅에서 이를 달성하는 한 가지 방법은 구성 스트림을 이용하는 것입니다.
GPU 스트림은 CPU 스레드와 유사하게 CPU와 GPU 간의 독립적인 실행 흐름을 나타냅니다. 스트림에서 작업은 호출 순서(예: FCF)에 따라 실행됩니다. 서로 다른 스트림 사이에서 작업은 리소스 가용성에 따라 병렬 또는 인터리브 방식으로 수행될 수 있습니다. 다음 그림은 다중 스트림 시나리오의 추상적 표현을 보여줍니다. 스트림의 작업은 단일 작업 대기열로 예약됩니다. 작업이 스트림 대기열의 맨 앞에 도달한 경우에만 다음 레벨 장치 스케줄러에 예약됩니다.

멀티 코어 스케줄링 계층 구조.
다음 레벨 스케줄러는 실행 큐(커널용) 또는 복사 큐(메모리 전송용)를 나타냅니다. 다시 말하지만, 이러한 대기열의 작업은 FCFS 방식으로 예약되지만 특정 장치 조건으로 인해 일부 경고가 발생합니다. 다음 표는 일부 GPU 스케줄링 규칙입니다(NVIDIA Jetson TX2 아키텍처에 대해 경험적으로 파생되고 여러 다른 NVIDIA 아키텍처에 대해 검증된 스케줄링 규칙 세트).
식별자 규칙
G1 관련 CUDA API 함수(메모리 전송 또는 커널 시작)가 호출되면 복사 작업 또는 커널이 해당 스트림의 스트림 대기열에 대기됩니다.
G2 커널이 스트림 대기열의 헤드에 도달하면 EE 대기열에 추가됩니다.
G3 EE 대기열의 헤드에 있는 코어가 완전히 예약되면 대기열에서 제거됩니다.
G4 커널의 모든 블록 실행이 완료되면 커널은 스트림 대기열에서 제외됩니다.
X1 EE 큐의 헤드에 있는 커널 블록만 할당할 수 있습니다.
R1 EE 대기열의 헤드에 있는 커널 블록은 리소스 제약 조건이 충족되는 경우에만 할당할 수 있습니다.
R2 EE 큐의 헤드에 있는 커널 블록은 일부 SM에서 사용 가능한 스레드 리소스가 충분한 경우에만 할당될 수 있습니다.
R3 EE 대기열의 헤드에 있는 커널 블록은 일부 SM에서 충분한 공유 메모리 리소스를 사용할 수 있는 경우에만 할당될 수 있습니다.
C1 복사 작업이 스트림 큐의 헤드에 도달하면 CE 큐에 대기됩니다.
C2 CE 대기열의 헤드에 있는 복사 작업은 CE에 할당할 수 있습니다.
C3 복사본이 GPU의 CE에 할당되면 CE 대기열의 헤드에 있는 복사 작업이 CE 대기열에서 종료됩니다.
C4 CE가 복사를 완료한 후 복사 작업은 스트림 큐에서 제거됩니다.
N1 다른 모든 플로우 큐에 대해 큐가 비어 있거나 헤드의 커널이 Kk 이후에 시작되면 빈 플로우 큐의 헤드에 있는 커널 Kk가 EE 큐에 대기됩니다.
N2 비어 있지 않은 흐름 큐의 헤드에 있는 커널 Kk는 빈 흐름 큐가 비어 있거나 헤드에 있는 커널이 Kk 이후에 시작되지 않는 한 EE 큐에 대기할 수 없습니다.
A1 커널은 스트림 우선순위와 일치하는 EE 대기열에만 대기열을 추가할 수 있습니다.
A2 모든 EE 큐의 헤드에 있는 커널 블록은 모든 높은 우선순위의 EE 큐(낮은 우선순위보다 높은 우선순위)가 비어 있는 경우에만 할당할 수 있습니다.
이러한 예약 규칙을 이해하는 것은 최대 리소스 활용도와 높은 시스템 처리량을 달성하는 데 중요합니다. 이러한 규칙은 일단 코어의 블록이 X1을 통해 GPU에 예약되기 시작하면 첫 번째 코어의 모든 블록이 예약될 때까지 다른 코어(G3)를 예약할 수 없음을 명시합니다. 이는 리소스 규칙(R1-R3) 중 하나를 충족하지 않아 첫 번째 코어가 실행 대기열에서 정지될 때 발생할 가능성이 높습니다. 그러나 실행 대기열의 후속 코어가 이러한 리소스 규칙을 충족하도록 구성되는 것은 전적으로 가능합니다. 따라서 장치 활용률을 향상시킬 수 있는 기회를 놓치게 되므로 실행 대기열 예약에 대한 보다 세부적인 접근 방식이 필요합니다. 비슷한 설명을 하지 않고 복제된 대기열에도 이러한 고려 사항이 존재하므로 대체 스케줄링 전략에 대한 유사한 조사가 필요하다고 주장합니다.
이전 연구는 고성능 및 에너지 효율성을 달성하기 위해 GPU 리소스 활용에 대한 추가 분석에 대한 동기를 제공합니다. 홍 씨와 김 씨는 논문에서 애플리케이션을 두 가지 주요 축, 즉 컴퓨팅 제약이 있는 애플리케이션과 메모리가 제한된 애플리케이션으로 분류하고 성능, 활용도, 에너지 효율성 간의 관계가 이러한 특성과 관련이 있음을 보여주었습니다. 컴퓨팅 바인딩된 애플리케이션은 확장성이 뛰어납니다. 고정된 문제 크기의 경우 애플리케이션에 더 많은 처리 코어가 제공되면 코어 수에 비례하여 속도 향상이 나타납니다(즉, 동일한 양의 작업이 더 짧은 시간에 수행됨). 반면, 메모리가 제한된 애플리케이션은 확장성이 약합니다. 이 경우 성능은 고정된 문제 크기에 의해 제한되며 더 많은 프로세서를 추가하면 문제 크기가 비례적으로 증가하는 경우(즉, 동시에 더 많은 작업이 수행되는 경우)에만 성능이 향상될 수 있습니다.
홍 씨와 김 씨는 애플리케이션에서 사용할 수 있는 최적의 코어 수를 도출하기 위해 이러한 스케일링 특성과 다양한 GPU 코어의 성능 및 전력 소비 간의 관계를 보여주었습니다. 이 접근 방식의 주장된 이점은 애플리케이션 유형에 따라 다양한 활용률에서 최적의 에너지 효율성을 달성할 수 있다는 것입니다. 컴퓨팅 바인딩된 애플리케이션의 경우 가장 좋은 지점은 전체 활용률이고, 메모리 바인딩된 애플리케이션의 경우 가장 좋은 지점은 이 이하입니다. 분명한 결론은 많은 애플리케이션이 최적의 성능을 달성하기 위해 GPU 리소스를 완전히 보완할 필요가 없다는 것입니다. 또한, 본 논문의 접근 방식의 목표는 단일 코어에 대한 최적의 코어 수를 결정하는 모델을 개발하고 에너지 효율성 향상을 성공적으로 입증하는 것이었습니다. 그러나 이 접근 방식은 동시 실행 시나리오를 다루지 않으며 활용도가 낮은 GPU 리소스의 잠재력을 활용하는 방법을 제안하지 않습니다.
아래 왼쪽 그림에 표시된 간단한 시나리오는 단일 코어 실행(즉, 독립 코어 간에 장치를 공유하지 않음)의 개념적 시나리오와 그에 따른 성능 및 활용도를 보여줍니다. 특히 기기 활용률은 62.5%에 불과하며, 계획된 최대 코어 생성 시간은 4시간 단위다. 그러나 동시 실행을 고려하면 아래 그림의 오른쪽과 같이 활용도는 83.3%로 증가하고 최대 makespan은 3시간 단위로 감소합니다. 표시된 시나리오는 특히 위에서 설명한 스케줄링 규칙 및 제약 조건을 고려할 때 복잡한 스케줄링 문제를 지나치게 단순화한 반면, GPU 컴퓨팅 아키텍처의 기능을 최대화하기 위한 새로운 기술을 분석하고 개발하기 위한 초기 동기를 제공합니다.

직렬 실행(왼쪽)과 동시 실행(오른쪽)의 성능 및 활용도 비교.
동시성을 활용하고 장치 활용도를 극대화하는 이점은 일반적인 GPU 장치의 전력 소비 특성을 고려할 때 더욱 검증됩니다. 위에서 언급한 대로 작업은 라운드 로빈 또는 세미 라운드 로빈 방식으로 장비의 SMX 장치에 분배됩니다. 따라서 실행 중에 전체 장치에 전원이 공급되며 일반적으로 파워 게이팅과 같은 전략은 적용되지 않습니다. 물론 스레드 작업, 메모리 액세스 등을 포함하여 커널 응용 프로그램의 최대 전력 소비를 결정하는 여러 요소가 있지만 우리는 일반적으로 최대 전력 소비가 사용되는 기본 장치 리소스의 전체 비율과 관련이 없다는 것을 관찰했습니다. 아래 이미지는 그러한 예를 보여줍니다.

블록 수 및 장치 활용도 증가를 위한 커널 런타임(왼쪽) 및 GPU 전력 소비(오른쪽).
이 경우 GPU 활용도가 낮아 커널의 최고 성능이 달성됩니다. 마찬가지로, 최대 전력 소비는 최저 활용도 수준에서 가능한 최대 활용도까지 약 5% 증가하며 이는 무시할 수 있는 증가입니다. 이는 관찰 내용을 실증적으로 검증하는 데 도움이 되며 시스템 처리량을 개선하기 위한 접근 방식, 즉 더 짧은 시간에 더 많은 작업을 완료하는 접근 방식이 전력 소비를 명시적으로 관리하는 기술을 도입하지 않고도 시스템 에너지 효율성에 긍정적인 영향을 미칠 것이라는 주장을 할 수 있게 해줍니다. 이러한 기회를 고려할 때 연구의 주요 초점은 시스템 처리량 및 리소스 활용도를 향상시키기 위해 독립적인 GPU 작업을 최적으로 스케줄링하는 것입니다. 위에서 언급한 에너지 효율성 외에도 이 접근 방식의 이점에는 평균 정규 처리 시간으로 측정한 향상된 각 작업 성능이 포함됩니다.
OS GPU 스케줄링은 사용자 공간과 커널 공간에서 고려할 수 있으며, 각각 4가지 스케줄링 방법이 있습니다.
먼저 사용자 공간 GPU 스케줄러의 소프트웨어 아키텍처를 고려하십시오. 다음 그림에서는 여러 아키텍처를 설명합니다.

사용자 공간에 구현된 API 기반 GPU 스케줄러를 위한 여러 소프트웨어 아키텍처.
- 집행을 통한 중앙 집중식 일정
위의 그림 (a)는 사용자 공간에서 GPU 스케줄링을 위한 일반적인 소프트웨어 아키텍처를 설명합니다. GPGPU API 호출은 각 작업의 GPGPU 스텁 라이브러리에 발행되고 스텁 라이브러리는 IPC 채널(예: UNIX 도메인 소켓, TCP/IP 소켓 등)을 통해 중앙 집중식 스케줄링 정책에 따라 요청을 서비스하는 GPGPU 스케줄링 데몬으로 API 요청을 리디렉션합니다. 데몬은 모든 API 호출을 자체적으로 실행하여 모든 일정 결정을 시행합니다.
혜택:
중앙 집중식 의사 결정으로 인해 일정 전략을 쉽게 구현할 수 있습니다.
예약된 API 호출은 GPGPU 예약 데몬 자체에 의해 실행되므로 예약 결정이 실행됩니다.
단점:
데몬은 작업을 구성하는 GPU 커널 코드를 포함하거나 로드할 수 있어야 합니다. 이는 데몬을 컴파일할 때 수행할 수 있습니다. GPU 커널 코드를 동적으로 로딩하는 것도 가능하지만 구현이 쉽지 않습니다.
IPC는 작업과 데몬 간의 메시지 전달로 인해 오버헤드를 발생시킵니다.
메모리 재매핑 기술을 사용하지 않는 한 GPU 커널 데이터는 IPC 채널을 통해 전송되어야 합니다. 카메라에서 데이터가 공급되는 보행자 감지 애플리케이션과 같은 데이터 집약적인 GPGPU 애플리케이션의 성능이 저하됩니다.
데몬 프로세스 자체를 예약해야 합니다. 이로 인해 추가적인 스케줄러 오버헤드가 발생합니다. 게다가 RTOS가 데몬이 구성 요소 부분에서 우선 순위 작업을 상속할 수 있는 메커니즘을 제공하지 않는 한 일정 가능성 분석은 간단하지 않습니다. 이 제한은 데몬의 우선순위를 높여 우회할 수 있으며(일정 가능성 분석에 영향을 미침) CPU를 데몬 전용으로 예약할 수 있습니다(다른 작업에서 CPU를 잃게 됨). 두 가지 접근 방식 모두 바람직하지 않습니다.
GViM, gVirtuS, vCUDA, rCUDA 및 MPS는 이 널리 사용되는 아키텍처를 채택합니다. 그러나 이들 중 어느 것도 실시간 GPU 스케줄링 전략을 구현하지 않습니다. IPC 채널을 통해 GPU 커널 데이터를 전송하는 오버헤드로 인해 데이터가 많은 응용 프로그램의 성능이 허용되지 않을 수 있습니다.
- 시행 없는 중앙 집중식 일정
위의 그림 (b)는 또 다른 데몬 기반 스케줄러를 보여줍니다. GPGPU API 호출은 삽입된 라이브러리에 의해 가로채어지고, 각 호출마다 라이브러리는 IPC 채널을 통해 GPU 스케줄링 데몬에 해당 GPU 엔진을 요청합니다. 라이브러리는 각 요청이 승인될 때까지 기다리고, 데몬은 중앙 집중식 예약 정책에 따라 요청을 승인하며, 필요한 리소스가 승인되면 삽입된 라이브러리는 가로채는 API 호출을 원래 GPGPU 런타임에 전달합니다.
혜택:
일정 결정이 중앙 집중화되고 GPU 커널 코드가 각 구성 요소 작업에 대해 로컬이므로 구현이 쉽습니다.
GPU 커널 데이터는 IPC 채널을 통해 복사되지 않습니다. 데이터 집약적인 GPGPU 애플리케이션은 잘 작동합니다.
단점:
GPU 스케줄링 결정을 실행할 수 없습니다. 오작동하거나 악의적인 작업은 삽입 라이브러리를 우회하고 GPGPU 런타임에 직접 액세스할 수 있습니다.
IPC는 메시지 전달 오버헤드를 도입합니다.
데몬 자체가 정리되어 있어야 합니다.
GPU 커널 입력 및 출력 데이터는 IPC 채널을 통과하지 않기 때문에 이 아키텍처는 데이터 집약적인 애플리케이션의 성능 이점을 달성하기 위해 예약 결정 실행을 희생합니다. 또한 이는 8가지 GPU 스케줄링 아키텍처 중 가장 구현하기 쉬운 아키텍처이며, 비실시간 GPU 스케줄러인 Windows 7 기반 프로토타입 PTask에 채택된 아키텍처입니다. RGEM은 또한 이 아키텍처를 채택하는 실시간 GPU 스케줄러이기도 합니다.
- 집행을 통한 협력 일정
위의 그림 (c)는 협력 GPU 스케줄러와 GPGPU 런타임 데몬의 소프트웨어 아키텍처를 설명합니다. 플러그인 라이브러리는 API 호출을 가로채고 각 작업에 있는 라이브러리의 각 인스턴스는 플러그인 라이브러리에 포함된 동일한 GPU 예약 알고리즘을 호출합니다. GPU 스케줄러 상태의 단일 인스턴스는 공유 메모리에 저장되며, 삽입된 라이브러리는 실제 실행을 위해 API 호출을 데몬에 전달합니다.
혜택:
각 작업이 GPU 스케줄러 상태에 직접 액세스할 수 있으므로 GPU 스케줄링이 효율적입니다.
일정 결정의 약한 실행. GPGPU 런타임 데몬은 GPU에 대한 모든 액세스를 중앙 집중화하지만 오작동이나 악의적인 작업은 협력 GPU 스케줄러를 우회하고 데몬에 직접 작업을 실행할 수 있습니다.
단점:
공유 GPU 스케줄러 상태에 대한 액세스는 작업 간에 조정(또는 동기화)되어야 합니다. 사용된 동기화 메커니즘에 따라 작업은 스케줄링 알고리즘을 실행하는 동안(교착 상태를 방지하기 위해) 비선점적으로 실행되어야 할 수도 있습니다. 이를 위해서는 선점을 일시적으로 비활성화하는 권한 있는 CPU 명령에 대한 RTO 지원 또는 액세스가 필요합니다.
오작동하거나 악의적인 작업으로 인해 공유 메모리의 데이터를 덮어쓸 수 있으므로 GPU 스케줄러 상태가 손상될 수 있습니다. 그러한 실패로부터 복구하는 것은 어려울 수 있습니다.
오작동하거나 악의적인 작업은 GPU 스케줄러를 우회하고 데몬에 요청을 확인하는 메커니즘이 없는 한 GPGPU 런타임 데몬에 직접 작업을 실행할 수 있습니다.
IPC는 메시지 전달 오버헤드를 도입합니다.
GPU 커널 데이터는 IPC 채널을 통해 전송되어야 합니다.
데몬 자체가 정리되어 있어야 합니다.
이 아키텍처의 IPC와 관련된 오버헤드로 인해 협력적 스케줄링의 잠재적 이점이 제거됩니다. 또한 GPU 스케줄러를 우회할 수 있으므로 스케줄링 결정을 수행하는 기능이 감소합니다. 이 아키텍처는 중앙 집중식 스케줄링(위의 a)에 비해 뚜렷한 이점이 없습니다.
- 집행 없는 협력 일정
위의 그림 (d)는 데몬을 사용하지 않는 협력 GPU 스케줄러의 소프트웨어 아키텍처를 보여줍니다. 삽입된 라이브러리는 API 호출을 가로채고 이전과 마찬가지로 작업이 동일한 GPU 스케줄링 알고리즘을 공동 실행하고 동일한 공유 스케줄러 상태에서 실행됩니다. 차단된 API 호출은 일정 시간에 원래 GPGPU 런타임으로 전달됩니다.
혜택:
IPC 관리비가 없습니다. 데이터 집약적인 GPGPU 애플리케이션은 잘 작동합니다.
스케줄할 데몬이 없습니다. 이는 실시간 분석을 단순화하고 RTO 지원을 줄입니다.
효율적인 GPU 스케줄링.
단점:
GPU 스케줄러 상태에 대한 액세스가 조정되어야 합니다.
GPU 스케줄러 상태는 쉽게 손상됩니다.
GPU 스케줄링 결정을 실행할 수 없습니다.
이는 연구된 가장 효율적인 사용자 공간 아키텍처입니다. 이는 모든 IPC 오버헤드를 방지하고 데몬과 함께 제공되는 모든 오버헤드 및 프로파일링 문제를 방지합니다. 그러나 이는 또한 8개 아키텍처 중 가장 취약하며 작업을 신뢰해야 합니다. 즉, GPU 스케줄러를 우회하지 않고 GPU 스케줄러 상태를 손상시키지 않아야 합니다.
다음으로 커널 공간에서 GPU 스케줄링을 살펴보세요.
사용자 공간의 GPU 스케줄링에는 몇 가지 약점이 있습니다. 한 가지 단점은 GPU 스케줄러 데이터 구조를 적절하게 보호하지 못할 수도 있다는 것입니다. GPU 스케줄러 상태가 동작 오류나 악의적인 작업으로 인해 손상될 수 있는 협력적 스케줄링 접근 방식의 경우입니다. 그러나 사용자 공간 스케줄링의 가장 큰 약점은 기본 RTO와 긴밀하게 통합할 수 없다는 점이며, 이로 인해 어느 정도 확신을 가지고 올바른 실시간 시스템을 구현하지 못할 가능성이 있습니다. RTOS는 실시간 작업이 사용자 공간 작업을 통해 다른 작업의 예약 우선순위에 영향을 미칠 수 있는 메커니즘을 제공할 수 있습니다(예: 우선순위 수정 진행 메커니즘이 있는 실시간 잠금 프로토콜 및 우선순위를 직접 조작하는 시스템 호출). 이를 활용하여 사용자 공간 GPU 스케줄러에 실시간 결정성을 추가할 수 있습니다. 그러나 이러한 메커니즘은 GPU 관련 우선순위 반전을 최소화하고 제한하는 데 충분하지 않을 수 있습니다.
많은 문제를 해결하는 능력은 사용자 공간에 따라 심각하게 제한됩니다. 이러한 문제는 GPU 스케줄러를 CPU 스케줄러 및 인터럽트 처리 서비스와 같은 RTOS 커널의 기타 운영 체제 구성 요소와 긴밀하게 통합함으로써 가장 잘 해결됩니다. 이러한 문제는 우리가 커널 공간 GPU 스케줄러를 고려하도록 동기를 부여합니다. 아래 그림은 커널 공간 GPU 스케줄러의 몇 가지 고급 소프트웨어 아키텍처를 설명합니다. 모든 방법은 RTO와 긴밀하게 통합되는 능력으로 인해 이점을 얻는 것으로 가정됩니다.

- 집행을 통한 중앙 집중식 일정
위의 그림 (a)는 중앙 집중식 스케줄러 데몬이 있는 소프트웨어 아키텍처를 보여줍니다. 아키텍처는 그림 3.1(a)에 표시된 것과 매우 유사하며 기능도 거의 동일합니다. 그러나 GPU 스케줄링 데몬은 이제 커널 공간에서 실행됩니다.
혜택:
GPU 커널 데이터는 IPC 채널을 통해 복사되지 않습니다. 이는 GPU 스케줄링 데몬이 구성 작업의 사용자 공간 메모리에 직접 액세스할 수 있기 때문에 가능합니다. 데이터 집약적인 GPGPU 애플리케이션은 잘 작동합니다.
일정 전략이 중앙 집중화되어 있습니다.
계획된 결정을 실행합니다.
단점:
커널 공간 GPGPU 런타임을 사용하지 못할 수 있습니다. 제조업체가 제공하는 모든 GPGPU 런타임은 사용자 공간에서만 실행됩니다.
데몬 프로세스 자체를 예약해야 합니다. 추가 시스템 오버헤드가 있지만 커널 공간 관점에서 볼 때 실시간 결정성을 보장하기 위해 데몬의 우선 순위를 적절하게 지정하는 데 더 많은 유연성이 있습니다.
데몬은 작업을 구성하는 GPU 커널 코드를 포함하거나 로드할 수 있어야 합니다.
IPC는 메시지 전달 오버헤드를 도입합니다.
이 아키텍처는 강제 중앙 집중식 스케줄링의 이점을 활용하므로 IPC 채널에서 GPU 커널 입력 및 출력 데이터를 셔틀할 필요가 없습니다. 이 접근 방식에서는 메시지 전달로 인해 여전히 일부 IPC 채널 오버헤드가 발생합니다. 그러나 이 접근 방식의 가장 큰 단점은 실용성입니다. 커널 공간 GPGPU 런타임은 일반적으로 사용할 수 없습니다. Gdev(위 그림 a 및 d의 하이브리드 아키텍처 사용)에서 알 수 있듯이 극복할 수 없는 과제는 아니지만 어렵습니다.
- 시행 없는 중앙 집중식 일정
위의 그림 (b)는 사용자 공간에 대한 아키텍처가 (b)의 아키텍처와 일치하는 GPU 스케줄링 데몬이 있는 또 다른 소프트웨어 아키텍처를 보여줍니다. 단, 데몬은 이제 커널 공간에서 실행됩니다.
혜택:
일반 사용자 공간 GPGPU 런타임을 사용합니다.
일정 전략이 중앙 집중화되어 있습니다.
GPU 커널 데이터는 IPC 채널을 통해 복사되지 않습니다.
혜택:
GPU 스케줄링 결정을 실행할 수 없습니다.
IPC는 메시지 전달 오버헤드를 도입합니다.
데몬 자체를 예약해야 합니다.
이 아키텍처는 커널 공간 중앙 집중식 스케줄링과 실제 제약 조건 간의 절충안을 제시합니다. 스케줄링 결정은 커널 공간 내에서 이루어지지만 사용자 공간 GPGPU 런타임을 사용하는 단일 작업에 의해 실행됩니다. 따라서 아키텍처는 비실시간 GPU 스케줄러인 PTask의 Linux 기반 프로토타입에 채택된 아키텍처인 스케줄링 결정을 강제할 수 없습니다.
- 집행을 통한 협력 일정
위의 그림 (c)는 협력 GPU 스케줄러의 소프트웨어 아키텍처를 설명합니다. GPGPU API 호출은 OS 시스템 호출을 통해 커널 공간 GPU 스케줄러를 호출하는 스텁 라이브러리로 라우팅됩니다. GPU 스케줄러 상태는 모든 작업에서 공유되지만 커널 공간 데이터 구조에 저장됩니다. 예약된 API 호출은 호출 작업의 프로그램 스레드를 사용하여 커널 공간 GPGPU 런타임에 의해 실행됩니다.
혜택:
GPU 스케줄러 상태가 보호됩니다. 협력적 사용자 공간 스케줄러와 달리 GPU 스케줄러 상태는 커널 공간 내에서 보호되며 잘못된 동작이나 악의적인 사용자 공간 작업으로 인해 손상될 수 없습니다.
커널 공간에서는 GPU 스케줄러 상태에 대한 동기식 액세스가 쉽지 않습니다. 비선점 방식으로 수행하기 위해 GPU 스케줄러 데이터 구조를 업데이트하는 경우 권한 상승이 필요하지 않습니다.
GPU 스케줄링이 효과적입니다.
계획된 결정을 실행합니다.
혜택:
- 커널 공간 GPGPU 런타임이 필요합니다.
이는 성능 관점에서 연구된 8개 아키텍처 중 가장 강력하며, 공동 일정 결정은 RTO에 의해 효율적이고 실행됩니다. GPGPU 런타임은 별도로 예약된 데몬 프로세스가 아닌 호출 작업의 프로그램 스택을 사용하여 커널 공간에서 실행됩니다. IPC 오버헤드는 없으며 유일한 제한은 커널 공간 GPGPU 런타임에 대한 의존성입니다.
- 집행 없는 협력 일정
위의 그림 (d)는 협력적 GPU 스케줄러를 위한 대체 소프트웨어 아키텍처를 보여줍니다. 삽입된 라이브러리는 API 호출을 가로채고 시스템 호출을 통해 커널 공간 GPU 스케줄러를 호출합니다. 이전과 마찬가지로 GPU 스케줄러 상태는 모든 작업에서 공유되며 오작동 및 악의적인 작업으로부터 보호됩니다. API 호출을 예약하기 위해 GPU 스케줄러는 삽입된 라이브러리에 제어권을 반환합니다. 삽입된 라이브러리는 사용자 공간 GPGPU 런타임을 사용하여 예약된 API 호출을 실행합니다.
혜택:
일반 사용자 공간 GPGPU 런타임을 사용합니다.
GPU 스케줄러 상태가 보호됩니다.
GPU 스케줄러 상태에 대한 액세스가 쉽게 동기화됩니다.
GPU 스케줄링이 효과적입니다.
단점:
- GPU 스케줄링 결정을 실행할 수 없습니다.
사용자 공간 GPGPU 런타임을 지원하기 위해 이 아키텍처는 GPGPU 런타임에 직접 액세스하여 삽입된 라이브러리를 우회하지 않고 신뢰 작업을 적용하는 기능을 희생합니다. 이러한 제한에도 불구하고 성능 측면에서는 여전히 강력한 아키텍처입니다. 이전 접근 방식과 마찬가지로 일정 결정은 유효합니다. 또한 IPC 또는 데몬과 관련된 오버헤드가 없습니다. 이 아키텍처는 운영 체제 수준 코드를 구현하려는 연구원이나 개발자에게 가장 실용적인 고성능 옵션입니다.
GPU 스케줄링과 관련된 기타 기타 기술에 대해 이야기해 보겠습니다.
아래 그림은 vHybrid라는 CPU-GPU 스케줄링 아키텍처입니다.

다음 그림은 klmirqd를 사용하는 GPU 마이크로 스레드 스케줄링 인프라를 보여줍니다.

GPUSync를 사용하는 작업에 대한 복잡한 실행 종속성 체인의 예:

혼합 플랫폼 구성:

아래쪽 절반의 오버헤드 처리에 대한 상위 수준 보기:

간접 오버헤드는 엔진의 임계 섹션 길이를 늘립니다.

콜백 오버헤드를 설명하는 스케줄링:

자세한 내용은 다음을 참조하세요.
고급 자동차 시스템의 애플리케이션을 갖춘 GPU에 대한 실시간 스케줄링
공유 실행 환경을 위한 GPU 리소스 최적화 및 스케줄링
16.4 GPU 드라이버
16.4.1 엔비디아
16.4.1.1 튜링 아키텍처
Turing은 PC 게임, 전문 그래픽 애플리케이션 및 딥 러닝 추론의 효율성과 성능을 크게 향상시킬 수 있는 새로운 코어 GPU 아키텍처를 제공하여 10년 만에 가장 큰 아키텍처 도약을 나타냅니다.
새로운 하드웨어 기반 가속기와 하이브리드 렌더링 방법을 사용하여 Turing은 래스터라이제이션, 실시간 레이 트레이싱, AI 및 시뮬레이션을 혼합하여 PC 게임에서 놀라운 사실감을 구현하고, 신경망을 기반으로 하는 놀라운 새로운 효과, 영화 수준의 대화형 경험, 복잡한 3D 모델을 만들거나 탐색할 때 유연한 상호 작용을 구현합니다.
핵심 아키텍처 내에서 Turing의 획기적인 그래픽 성능 향상을 가능하게 하는 주요 요소는 향상된 셰이더 실행 효율성을 갖춘 새로운 GPU 프로세서(Streaming Multiprocessor SM) 아키텍처와 최신 GDDR6 메모리 기술에 대한 지원을 포함하는 새로운 메모리 시스템 아키텍처입니다.
ImageNet Challenge와 같은 이미지 처리 애플리케이션은 딥 러닝의 첫 번째 성공 사례 중 하나이므로 AI가 많은 중요한 그래픽 문제를 해결할 수 있는 잠재력을 가지고 있다는 것은 놀라운 일이 아닙니다. Turing의 Tensor 코어는 클라우드 기반 시스템에 대한 빠른 AI 추론을 제공하는 것 외에도 게임 및 전문 그래픽에 놀라운 그래픽 효과를 제공하는 새로운 딥 러닝 기반 신경 서비스 세트를 지원합니다.

Turing의 혁신적인 새로운 기능.
NVIDIA Turing은 세계에서 가장 발전된 GPU 아키텍처이며, 최고급 TU102 GPU에는 TSMC의 12nm FFN(FinFET NVIDIA) 고성능 제조 공정에서 제조된 186억 개의 트랜지스터가 포함되어 있습니다. GeForce RTX 2080 Ti Founders Edition GPU는 다음과 같은 탁월한 컴퓨팅 성능을 제공합니다.
14.2 TFLOPS의 최고 단정밀도(FP32) 성능.
28.5 TFLOPS의 최고 반정밀도(FP16) 성능.
14.2 독립적인 정수 실행 장치를 통해 FP와의 TIPS1 동시성.
113.8 텐서TFLOPS.
10기가 광선/초.
78테라 RTX-OPS.
Quadro RTX 6000은 전문적인 워크플로우를 위해 설계된 탁월한 컴퓨팅 성능을 제공합니다.
16.3 TFLOPS의 최고 단정밀도(FP32) 성능.
32.6 TFLOPS의 최고 반정밀도(FP16) 성능.
16.3 TIPS 독립적인 정수 실행 장치를 통한 FP와의 동시성.
130.5 텐서 TFLOPS.
10기가 광선/초.
84테라 RTX-OPS.
또한 새로운 기능에는 새로운 스트리밍 멀티프로세서(SM), Turing Tensor Core, 실시간 광 추적 가속, 새로운 셰이딩 개선 사항(메시 셰이딩, 가변 속도 셰이딩, 텍스처 공간 셰이딩, 멀티 뷰 렌더링), 딥 러닝, GDDR6 등이 포함됩니다.

튜링 아키텍처 TU102 GPU.

Turing TU102/TU104/TU106 스트리밍 멀티프로세서(SM).

많은 워크로드를 분석한 결과 100개의 부동 소수점 연산마다 평균 36개의 정수 연산이 수행된 것으로 나타났습니다.

새로운 공유 메모리 아키텍처.

다양한 워크로드에서 Pascal에 비해 Turing Shading의 성능 속도가 향상되었습니다.

새로운 Turing Tensor Core는 인공 지능 추론을 위한 다중 정밀도를 제공합니다.

튜링 GDDR6.
Turing GPU는 새로운 GDDR6 메모리 하위 시스템 외에도 더 크고 빠른 L2 캐시를 추가합니다. TU102 GPU에는 TITAN Xp에 사용된 이전 세대 GP102 GPU가 제공하는 3MB L2 캐시의 두 배인 6MB L2 캐시가 함께 제공됩니다. TU102는 또한 GP102보다 훨씬 높은 L2 캐시 대역폭을 제공합니다. 이전 세대 NVIDIA GPU와 마찬가지로 Turing의 각 ROP 파티션에는 8개의 ROP 장치가 포함되어 있으며 각 ROP 장치는 하나의 색상 샘플을 처리할 수 있습니다. 완전한 TU102 칩에는 12개의 ROP 파티션이 포함되어 있으며 총 96개의 ROP가 있습니다.
NVIDIA GPU는 데이터가 프레임 버퍼 메모리에 기록될 때 메모리 대역폭 요구 사항을 줄이기 위해 여러 가지 무손실 메모리 압축 기술을 활용합니다. GPU의 압축 엔진에는 데이터의 특성에 따라 데이터를 압축하는 가장 효율적인 방법을 결정하는 다양한 알고리즘이 있으며, 메모리에 기록되고 메모리에서 L2 캐시로 전송되는 데이터의 양을 줄이고 클라이언트(예: 텍스처 단위)와 프레임 버퍼 간에 전송되는 데이터의 양을 줄입니다. Turing은 Pascal의 가장 진보된 메모리 압축 알고리즘을 더욱 향상시켜 GDDR6의 원래 데이터 전송 속도 증가를 기반으로 유효 대역폭을 더욱 향상시킵니다. 아래 그림에서 볼 수 있듯이 원시 대역폭이 증가하고 트래픽이 감소한다는 것은 Turing의 유효 대역폭이 Pascal에 비해 50% 증가했음을 의미하며, 이는 아키텍처 균형을 유지하고 새로운 Turing SM 아키텍처가 제공하는 성능을 지원하는 데 중요합니다.

Turing TU102 기반 RTX 2080 Ti의 메모리 하위 시스템 및 압축(트래픽 감소) 개선은 Pascal GP102 기반 1080 Ti에 비해 약 50% 효과적인 대역폭 개선을 제공합니다.
또한 Turing은 실시간 Ray Tracing 지원 추가와 하이브리드 파이프라인 도입도 개척했습니다.


Turing GPU는 다음과 같은 렌더링 및 비렌더링 작업에 사용되는 레이 트레이싱 기술을 가속화할 수 있습니다.
반사와 굴절.
그림자와 앰비언트 오클루전(AO).
글로벌 일루미네이션.
즉각적인 오프라인 라이트맵 베이킹.
아름다운 사진과 고품질 미리보기.
포비티드 VR 렌더링을 위한 메인 라이트.
오클루전 컬링.
물리학, 충돌 감지, 입자 시뮬레이션.
오디오 시뮬레이션(예: NVIDIA VRWorks 오디오는 OptiX API를 기반으로 구축됨)
AI 가시성 쿼리.
엔진 내 경로 추적(비실시간)은 실시간 렌더링 기술 및 노이즈 제거기, 재료 합성 및 장면 조명 조정을 위한 참조 스크린샷을 생성합니다.
하드웨어 가속이 없으면 레이 트레이싱에는 잠재적으로 삼각형에 도달할 때까지 BVH 구조의 더 작은 경계 상자를 지속적으로 테스트하기 위해 광선당 수천 개의 소프트웨어 명령 슬롯이 필요합니다. 이는 하드웨어 기반 레이 트레이싱 가속 없이는 GPU에서 실시간으로 불가능할 계산 집약적인 프로세스입니다(아래 이미지 참조).


아래 그림은 전통적인 래스터라이제이션 및 음영처리 프로세스를 보여줍니다. 3D 장면은 래스터라이제이션되어 화면 공간의 픽셀로 변환됩니다. 픽셀은 가시성, 모양 음영 및 깊이에 대해 테스트됩니다. 모든 작업은 동일한 화면 공간 픽셀 그리드, 동일한 픽셀에서 발생합니다.

TSS(텍스처 공간 셰이딩)를 사용하면 가시성 샘플링(래스터라이제이션 및 z-테스트)과 모양 샘플링(셰이딩)의 두 가지 주요 작업을 분리하여 서로 다른 속도, 서로 다른 샘플링 그리드, 심지어 서로 다른 타임라인에서도 수행할 수 있습니다. 셰이딩 프로세스는 더 이상 화면 공간 픽셀에 직접 연결되지 않고 텍스처 공간에서 발생합니다. 아래 이미지에서 형상은 여전히 래스터라이제이션되어 화면 공간 픽셀을 생성하고 가시성 테스트는 여전히 화면 공간에서 수행됩니다. 그러나 화면 공간에서 음영 처리하는 대신 출력 픽셀을 덮어야 하는 텍스처가 발견됩니다. 즉, 화면 공간 픽셀의 공간은 별도의 텍스처 공간에 매핑되고 관련 텍셀은 텍스처 공간에 음영 처리됩니다. 텍스처 공간에 매핑하는 것은 LOD 및 이방성 필터링 등에 대해 동일한 컨트롤을 사용하는 표준 텍스처 매핑 작업입니다. 최종 화면 공간 픽셀을 생성하기 위해 음영 텍스처에서 샘플링합니다. 텍스처는 샘플 요청을 기반으로 요청 시 생성되며, 참조된 텍스처에 대해서만 값이 생성됩니다.

TSS의 예시적인 사용 사례는 VR 렌더링의 효율성을 향상시키는 것입니다. 아래 그림은 VR 렌더링에서 TSS를 사용하는 사례의 예를 보여줍니다. VR에서는 한 쌍의 입체 영상이 렌더링되며, 왼쪽 눈에 보이는 거의 모든 요소가 오른쪽 눈에도 표시됩니다. TSS를 사용하면 전체 왼쪽 눈 보기를 음영 처리한 다음 완성된 왼쪽 눈 보기에서 샘플링하여 오른쪽 눈 보기를 렌더링할 수 있습니다. 오른쪽 눈 보기에서는 유효한 샘플이 발견되지 않은 경우에만 새 텍스처를 음영처리하면 됩니다(예를 들어 배경 개체가 왼쪽 눈 관점의 보기에서는 가려져 있지만 오른쪽 눈에는 보입니다).

**다중 뷰 렌더링(MVR)**을 사용하면 개발자는 여러 시점에서 장면을 효율적으로 그릴 수 있으며 심지어 단일 패스에서 다양한 포즈로 캐릭터의 여러 인스턴스를 그릴 수도 있습니다. Turing 하드웨어는 프로세스당 최대 4개의 보기와 API 수준에서 최대 32개의 보기를 지원합니다. 지오메트리를 추출하고 한 번만 음영 처리함으로써 Turing은 여러 버전을 렌더링할 때 삼각형 및 관련 버텍스 어트리뷰트을 최적으로 처리할 수 있습니다. D3D12 보기 인스턴스화 API를 통해 액세스하면 개발자는 SV_ViewID 변수를 사용하여 다양한 변환 행렬을 인덱싱하고, 다양한 혼합 가중치를 참조하거나, 작업 중인 보기에 따라 원하는 셰이더 동작을 제어할 수 있습니다.
아래 이미지는 두 개의 틸트 패널이 사용되는 200° FOV HMD의 구성을 보여 주며 MVR의 표현력이 더 요구됩니다. MVR의 유연성 덕분에 표준 입체형 VR 디스플레이를 보다 정밀하게 보정하여 개별 사용자의 얼굴에 맞출 수 있습니다. 입체 렌더링에서는 눈이 서로 오프셋되어 있다는 간단한 가정이 있습니다.

200° FOV HMD는 두 개의 틸트 패널을 사용하고 MVR의 이점을 활용합니다.

MVR 단일 패스 계단식 섀도우 맵 렌더링.
16.4.1.2 암페어 아키텍처
NVIDIA Ampere 아키텍처 GPU 제품군의 최신 멤버인 GA102 및 GA104는 Ampere 아키텍처 GPU의 새로운 NVIDIA "GA10x" 클래스의 일부입니다. GA10x GPU는 혁신적인 NVIDIA Turing GPU 아키텍처를 기반으로 합니다.
GeForce RTX 3090은 GeForce RTX 시리즈 중 최고 성능의 GPU이며 8K HDR 게임용으로 설계되었습니다. 10496개의 CUDA 코어, 24GB GDDR6X 메모리 및 새로운 DLSS 8K 모드를 통해 8K@60fps에서 성능을 발휘할 수 있습니다. GeForce RTX 3080은 GeForce RTX 2080보다 2배 높은 성능을 발휘하여 GPU 역사상 가장 큰 세대 도약을 달성했습니다. GeForce RTX 3070의 성능은 NVIDIA의 이전 세대 플래그십 GPU인 GeForce RTX 2080 Ti와 비슷합니다. GA10x GPU의 새로운 HDMI 2.1 및 AV1 디코딩 기능을 통해 사용자는 HDR을 사용하여 8K 속도로 콘텐츠를 스트리밍할 수 있습니다.
NVIDIA A40 GPU는 오늘날의 디자인, 창의적, 과학적 과제를 해결하기 위해 동급 최고의 전문 그래픽과 강력한 컴퓨팅 및 AI 가속을 결합하여 데이터 센터의 성능과 다중 워크로드 기능에 있어서 혁신적인 도약입니다. RTX A6000과 동일한 코어 수와 메모리 크기를 갖춘 A40은 차세대 가상 워크스테이션과 서버 기반 워크로드를 지원합니다. NVIDIA A40은 이전 세대보다 에너지 효율성이 2배 더 높아 전문가에게 레이 트레이싱 렌더링, 시뮬레이션, 가상 제작 등을 위한 가장 진보된 기능을 제공합니다.

Ampere GA10x 아키텍처는 큰 도약입니다.
GA102의 주요 기능에는 2x FP32 프로세싱, 2세대 RT Core, 3세대 Tensor Core, GDDR6X 및 GDDR6 메모리, PCIe Gen 4 등이 포함됩니다.
이전 NVIDIA GPU와 마찬가지로 GA102는 GPC(그래픽 처리 클러스터), TPC(텍스처 처리 클러스터), SM(스트리밍 멀티프로세서), ROP(래스터 연산자) 및 메모리 컨트롤러로 구성됩니다. 전체 GA102 GPU에는 7개의 GPC, 42개의 TPC 및 84개의 SM이 포함되어 있습니다.
GPC는 주요 고급 하드웨어 블록이며 모든 주요 그래픽 처리 장치는 GPC 내부에 있습니다. 각 GPC에는 전용 래스터 엔진이 포함되어 있으며 이제 NVIDIA Ampere Architecture GA10x GPU의 새로운 기능인 2개의 ROP 파티션(각각 8개의 ROP 장치 포함)도 포함됩니다. GPC에는 6개의 TPC가 포함되어 있으며, 각 TPC에는 2개의 SM과 PolyMorph 엔진이 포함되어 있습니다.

GA102 GPU에는 168개의 FP64 장치(SM당 2개)도 있으며 FP64 TFLOP 속도는 FP32 작동 TFLOP 속도의 1/64입니다. FP64 Tensor Core 코드를 포함하여 FP64 코드가 있는 모든 프로그램이 올바르게 실행되도록 보장하기 위해 소수의 FP64 하드웨어 장치가 포함되어 있습니다.
GA10x GPU의 각 SM에는 128개의 CUDA 코어, 4개의 3세대 Tensor 코어, 256KB 레지스터 파일, 4개의 텍스처 유닛, 2세대 레이 트레이싱 코어, 128KB의 L1/공유 메모리가 포함되어 있으며, 이는 컴퓨팅 또는 그래픽 워크로드의 요구 사항에 따라 다양한 용량으로 구성할 수 있습니다. GA102의 메모리 하위 시스템은 12개의 32비트 메모리 컨트롤러(총 384비트)로 구성되며, 각 32비트 메모리 컨트롤러와 쌍을 이루는 512KB의 L2 캐시, 전체 GA102 GPU에서 총 용량은 6144KB입니다.
Ampere 아키텍처는 ROP에서도 최적화를 수행합니다. 이전 NVIDIA GPU에서 ROP는 메모리 컨트롤러 및 L2 캐시에 연결되었습니다. GA10x GPU부터 ROP는 GPC의 일부이며 총 ROP 수를 늘리고 스캔 변환 프런트엔드와 래스터 작업 백엔드 간의 처리량 불일치를 제거하여 래스터 작업 성능을 향상시킵니다. GPC당 7개의 GPC 및 16개의 ROP 장치를 갖춘 전체 GA102 GPU는 이전 세대 TU102와 같은 384비트 메모리 인터페이스 GPU에서 사용할 수 있었던 96개의 ROP 대신 112개의 ROP로 구성됩니다. 이 방법은 다중 샘플 앤티앨리어싱, 픽셀 채우기 속도 및 혼합 성능을 향상시킵니다.
SM 아키텍처 측면에서 Turing SM은 NVIDIA의 첫 번째 SM 아키텍처이며 레이 트레이싱 작업을 위한 전용 코어를 포함합니다. Volta GPU에는 텐서 코어가 도입되었으며 Turing에는 향상된 2세대 텐서 코어가 포함되어 있습니다. Turing 및 Volta SM이 지원하는 또 다른 혁신은 FP32 및 INT32 작업의 병렬 실행입니다. GA10x SM은 위의 모든 기능을 개선하는 동시에 강력한 새 기능을 많이 추가합니다. 이전 GPU와 마찬가지로 GA10x SM은 4개의 처리 블록(또는 파티션)으로 나뉘며, 각 블록에는 64KB 레지스터 파일, L0 명령 캐시, 워프 스케줄러, 스케줄링 장치, 수학 및 기타 장치 세트가 있습니다. 4개의 파티션은 128KB L1 데이터 캐시/공유 메모리 하위 시스템을 공유합니다. 파티션당 2개의 2세대 텐서 코어를 포함하여 총 8개의 텐서 코어를 포함하는 TU102 SM과 달리 새로운 GA10x SM은 파티션당 1개의 3세대 텐서 코어를 포함하여 총 4개의 텐서 코어를 포함합니다. 각 GA10x 텐서 코어는 Turing 텐서 코어보다 2배 더 강력합니다. Turing에 비해 GA10x SM의 1차 데이터 캐시와 공유 메모리를 합친 용량은 33% 더 큽니다. 그래픽 워크로드의 경우 캐시 파티션 용량이 Turing의 두 배로 32KB에서 64KB로 증가합니다.

GA10x 스트리밍 멀티프로세서(SM).
GA10x SM은 Turing 지원 2단 FP16(HFMA) 작동을 계속 지원합니다. TU102, TU104 및 TU106 Turing GPU와 유사하게 표준 FP16 작업은 GA10x GPU의 텐서 코어에 의해 처리됩니다. FP32 처리량의 비교 X 요소는 다음과 같습니다.
튜링 GA10x
FP32 1X 2X
FP16 2X 2X
앞서 언급했듯이 이전 세대 Turing 아키텍처와 마찬가지로 GA10x는 공유 메모리, L1 데이터 캐시 및 텍스처 캐시를 위한 통합 아키텍처를 갖추고 있습니다. 이 통합 설계는 워크로드에 따라 재구성되어 필요에 따라 L1 또는 공유 메모리에 더 많은 메모리를 할당할 수 있습니다. 레벨 1 데이터 캐시 용량이 SM당 128KB로 증가되었습니다. 컴퓨팅 모드에서 GA10x SM은 다음 구성을 지원합니다.
128KB L1 + 0KB 공유 메모리
120KB L1 + 8KB 공유 메모리
112KB L1 + 16KB 공유 메모리
96KB L1 + 32KB 공유 메모리
64KB L1 + 64KB 공유 메모리
28KB L1 + 100KB 공유 메모리
Ampere 아키텍처의 RT Core는 광선/삼각형 교차 테스트에서 Turing의 RT Core보다 두 배 빠릅니다.

GA10x GPU는 RT 코어와 그래픽 또는 RT 코어와 컴퓨팅 워크로드를 각 GA10x GPU SM에서 동시에 처리할 수 있는 새로운 기능을 통해 이전 NVIDIA GPU의 비동기 컴퓨팅 기능을 향상시킵니다. GA10x SM은 두 가지 컴퓨팅 워크로드를 동시에 처리할 수 있으며 이전 GPU 세대와 같은 동시 컴퓨팅 및 그래픽에 국한되지 않으므로 컴퓨팅 기반 노이즈 제거 알고리즘과 같은 시나리오를 RT Core 기반 레이 트레이싱 작업과 동시에 실행할 수 있습니다.

Turing 아키텍처와 비교하여 NVIDIA Ampere 아키텍처는 동일한 게임에서 동일한 프레임을 렌더링할 때 성능을 크게 향상시킬 수 있습니다.

위: Turing 기반 RTX 2080 Super GPU에서 셰이더 코어(CUDA 코어), 셰이더 코어 + RT 코어, 셰이더 코어 + RT 코어 + 텐서 코어만 사용하는 Wolfenstein: Youngblood의 프레임입니다. 다른 RTX 처리 코어를 추가하면 프레임 시간이 점차 감소합니다.
하단: Ampere 아키텍처 기반의 RTX 3080 GPU는 셰이더 코어(CUDA 코어), 셰이더 코어 + RT 코어, 셰이더 코어 + RT 코어 + 텐서 코어만을 사용하여 Wolfenstein: Youngblood의 프레임을 렌더링합니다.

GA10x RT Core는 Turing RT Core에 비해 광선/삼각형 교차 테스트 속도를 두 배로 높이고 레이 트레이싱 모션 블러 작업을 지원하기 위해 새로운 보간 삼각형 위치 가속 장치를 추가합니다.
희소성이 활성화된 GeForce RTX 3080은 밀도가 높은 Tensor 코어 작업을 갖춘 GeForce RTX 2080 Super에 비해 FP16 Tensor 코어 작업의 최대 처리량을 2.7배 제공합니다.

세밀하게 구조화된 희소성은 0이 아닌 4개 패턴 중 2개 패턴을 사용하여 훈련 가중치를 잘라내고, 0이 아닌 가중치를 미세 조정하는 간단한 일반적인 방법이 뒤따릅니다. 데이터 공간과 대역폭을 2배로 줄이기 위해 가중치가 압축되고, 희소 텐서 코어 연산은 0을 건너뛰어 수학 처리량을 두 배로 늘립니다. (아래 사진)

아래 그림은 GDDR6(왼쪽)과 GDDR6X(오른쪽) 간의 데이터 아이 비교를 보여줍니다. GDDR6X 인터페이스는 GDDR6 주파수의 절반으로 동일한 양의 데이터를 전송할 수 있습니다. 또는 특정 작동 주파수에서 GDDR6X는 GDDR6보다 유효 대역폭을 두 배로 늘릴 수 있습니다.

GDDR6X는 PAM4 신호를 사용하여 성능과 효율성을 향상시킵니다.
PAM4 신호로 인한 신호 대 잡음비 문제를 해결하기 위해 고속 신호 전송을 제한하기 위해 MTA(Maximum Transmission Abolition, 아래 그림 참조)라는 새로운 코딩 방식이 개발되었습니다. MTA는 신호가 최고 수준에서 최저 수준으로 또는 그 반대로 전환되는 것을 방지하여 인터페이스 신호 대 잡음비를 향상시킵니다. 이는 인코딩 핀에 전송된 바이트 중 데이터 버스트(시간 인터리브)의 일부를 각 핀에 할당한 다음 신중하게 선택한 코드워드를 사용하여 데이터 버스트의 나머지 부분을 최대 변환 없이 시퀀스로 매핑함으로써 이를 수행합니다. 또한 새로운 인터페이스 교육, 적응 및 균등화 체계가 도입되었습니다. 마지막으로 패키지 및 PCB 설계에는 더 높은 데이터 속도를 달성하기 위한 신중한 계획과 포괄적인 신호 및 전력 무결성 분석이 필요합니다.

기존 스토리지 모델에서는 게임 데이터를 하드 디스크에서 읽은 다음 시스템 메모리와 CPU에서 전송한 다음 GPU로 전송하므로 IO가 게임의 성능 병목 현상이 되는 경우가 많습니다.

기존 스토리지 모델을 사용하면 게임 압축 해제 시 Threadripper CPU의 코어 24개를 모두 사용할 수 있습니다. 최신 게임 엔진은 기존 스토리지 API의 기능을 뛰어넘었습니다. 차세대 입출력 아키텍처가 필요합니다. 데이터 전송 속도는 회색 막대이고, 필요한 CPU 코어는 검은색/파란색 블록입니다. 데이터를 압축해야 하는데 CPU가 따라잡을 수 없습니다.

NVIDIA RTX IO는 최신 게임에 필요한 복잡한 워크로드와 최첨단 NVMe SSD를 갖춘 게임용 PC용으로 설계된 차세대 스토리지 아키텍처인 Microsoft의 곧 출시될 DirectStorage API에 연결됩니다. 요약하면, 게임용으로 특별히 맞춤화된 간소화되고 병렬화된 API는 IO 오버헤드를 크게 줄이고 NVMe SSD에서 RTX IO 지원 GPU까지 성능/대역폭을 최대화할 수 있습니다. 특히 NVIDIA RTX IO는 GPU 기반 무손실 압축 해제 기능을 제공하므로 DirectStorage를 통한 읽기가 압축된 상태로 유지되고 압축 해제를 위해 GPU로 전달됩니다. 이 기술은 CPU에서 로드를 제거하고, 보다 효율적이고 압축된 형태로 데이터를 메모리에서 GPU로 이동하며, I/O 성능을 최대 2배까지 향상시킵니다.

RTX IO는 100배의 처리량과 20배의 CPU 사용률을 제공합니다. 데이터 전송 속도는 회색 및 녹색 막대이며, 필요한 CPU 코어는 검은색/파란색 블록입니다.

레벨 로딩 시간 비교. 부하 테스트는 24코어 Threadripper 3960x 플랫폼, 프로토타입 Gen4 NVMe m.2 SSD, 알파 소프트웨어에서 실행되었습니다.
16.4.1.3 누보
누보(Nouveau)는 프랑스어로 '새로운'이라는 뜻이다. Nouveau 프로젝트는 nVidia 카드용 고품질의 무료/무료 소프트웨어 드라이버를 구축하는 것을 목표로 합니다. Nouveau는 Linux 커널 KMS 드라이버(Nouveau), Mesa의 Gallium3D 드라이버 및 Xorg DDX(xf86 비디오 Nouveau)로 구성됩니다. 커널 구성 요소도 NetBSD로 이식되었습니다. 공식 웹사이트는 https://nouveau.freedesktop.org/index.html입니다.
2D/3D 가속은 모든 GPU(GA10x 제외)에서 지원되고, 비디오 디코딩 가속은 대부분의 Maxwell 이전 카드에서 지원되며, 수동 성능 수준 선택은 GM10x Maxwell, Kepler 및 Tesla G94-GT218 GPU에서 지원됩니다. 요즘 펌웨어에서는 필요한 액세스 권한을 얻으려면 NVIDIA 서명이 필요하기 때문에 GM20x 및 최신 GPU가 다시 잠길 희망은 거의 없습니다. 최신 업데이트는 2021년 1월입니다. GA10x 커널 모드 설정 지원이 Linux 5.11에 병합되었습니다.
Nouveau는 원래 Mesa 3D의 DRI(직접 렌더링 인프라)를 사용하여 3D 컴퓨터 그래픽을 렌더링했는데, 이는 3D 애플리케이션에서 직접 그래픽 처리 장치(GPU)를 사용하여 가속화된 3D 드로잉을 허용했습니다. 그러나 2008년 2월에 DRI 지원 작업이 중단되고 새로운 Gallium3D로 이전되었습니다. 2013년 9월 23일, Nvidia는 새로운 Nvidia GPU의 기성품 가용성에 영향을 미치는 영역을 해결하기 위해 GPU에 대한 일부 문서를 공개할 것이라고 공개적으로 발표했습니다. 2016년 7월 9일, Red Hat 직원 Ben Skeggs는 GeForce GTX 1070 및 GeForce GTX 1080 브랜드 그래픽 카드의 Pascal 기반 GP104 칩에 대한 지원을 Linux 커널에 추가하는 패치를 제출했습니다. XDC2016에서는 2016년 현황과 향후 작업을 소개하였고, OpenCL의 새로운 작업 현황을 FOSDEM에 공개하였습니다. 2019년에 NVidia는 Kepler, Maxwell, Pascal 및 Volta 칩셋에 대한 일부 문서를 제공했습니다.
Nouveau 외에도 NVIDIA 그래픽 카드를 지원하는 드라이버에는 pscnv, DirectFB nVidia 드라이버, BeOS/Haiku nVidia 드라이버, Utah-GLX, xfree 3.3.3 nvidia 드라이버 등이 포함됩니다. 2022년 5월 NVIDIA는 최신 NV GPU를 지원하는 Linux 커널 드라이버 모듈을 출시했습니다. 소스 코드는 NVIDIA Linux Open GPU 커널 모듈 소스에 있습니다.
16.4.2 AMD
AMD Radeon 소프트웨어는 고급 Micro Devices 그래픽 카드 및 APU용 장치 드라이버 및 유틸리티 소프트웨어 패키지입니다. 그래픽 사용자 인터페이스는 Electron으로 구축되었으며 64비트 Windows 및 Linux 배포판과 호환됩니다.
이 소프트웨어는 이전에는 AMD Radeon 설정, AMD Catalyst 및 ATI Catalyst로 알려졌습니다. AMD Radeon 소프트웨어는 비디오 디코딩(UVD(Unified Video Decoder)) 및 비디오 인코딩(VCE(Video Coding Engine))을 위한 디스플레이 컨트롤러 및 SIP 블록을 포함하여 렌더링을 위한 명령 코드 외에도 GPU 또는 APU 칩의 모든 기능 블록을 지원하도록 설계되었습니다. 장치 드라이버는 사운드 관련 계산을 수행하기 위한 SIP 블록인 AMD TrueAudio도 지원합니다.
Radeon 소프트웨어에는 게임 프로필 관리, 오버클러킹 및 언더클러킹, 성능 모니터링, 녹화 및 스트리밍, 캡처된 비디오 및 스크린샷 관리, 소프트웨어 업데이트 알림, 업그레이드 어드바이저 등의 기능이 포함되어 있습니다. 또한 다중 모니터, 비디오 가속, 오디오 가속, 절전, GPGPU 및 기타 기능도 지원합니다. 또한 D3D, Mantle, OpenGL, Vulkan 및 OpenCL과 같은 그래픽 API를 지원합니다.
GCN은 하드웨어와 드라이버 지원의 조합을 통해 캐시 일관성과 함께 가상 메모리를 도입합니다. 가상 메모리는 메모리 관리의 가장 어려운 측면을 제거하고 새로운 기능을 제공합니다. 고성능 그래픽 및 마이크로프로세서에 대한 AMD의 고유한 전문 지식은 GCN의 가상 메모리 모델이 x86과 호환되도록 신중하게 정의되었기 때문에 특히 유용합니다. 이러한 움직임은 초기 제품에서 CPU와 개별 GPU 간의 데이터 이동을 단순화하고, 더 중요한 것은 CPU와 GPU가 원활하게 공유하는 단일 주소 공간을 위한 길을 열어준다는 것입니다. 데이터 복사보다 공유는 성능과 에너지 효율성에 매우 중요하며 AMD APU(가속 처리 장치)와 같은 이기종 시스템의 핵심 요소입니다.
GCN 명령 프로세서는 드라이버로부터 고급 API 명령을 수신하고 이를 다른 처리 파이프라인에 매핑하는 역할을 합니다. GCN에는 두 가지 주요 파이프라인이 있습니다. ACE(Asynchronous Compute Engine)는 컴퓨팅 셰이더를 관리하고, 그래픽 명령 프로세서는 그래픽 셰이더와 고정 기능 하드웨어를 처리합니다. 각 ACE는 병렬 명령 스트림을 처리할 수 있으며 그래픽 명령 프로세서는 각 셰이더 유형에 대해 별도의 명령 스트림을 제공할 수 있으므로 GCN의 멀티태스킹을 활용하기 위해 많은 양의 작업이 생성됩니다.

AMD GCN 아키텍처의 캐시 계층 구조.
16.4.3 인텔
아래 다이어그램은 각 구성 요소에 대한 간략한 설명과 함께 인텔 그래픽 플랫폼의 전체 기능 스택에 필요한 구성 요소를 보여줍니다.

인텔 그래픽 컨트롤러: HDR 콘텐츠 디코딩 및 렌더링을 위해 7세대 Intel Core 프로세서 이상에 통합된 그래픽 엔진 하드웨어입니다. 디스플레이 엔진은 HDMI 및 DisplayPort 케이블을 통해 HDR 신호를 HDR 디스플레이로 전송합니다.
인텔 그래픽 드라이버: 위에서 언급한 해당 하드웨어 외에 특정 드라이버 버전이 필요하며 항상 intel.com, PC OEM 웹사이트 또는 Windows 업데이트를 통해 최신 그래픽 드라이버를 다운로드하는 것이 좋습니다.
운영 체제: Windows 10 운영 체제의 적절한 버전인 Windows 10 Fall Creators Update(RS3)는 모든 최신 버전에서 작동하는 최소 운영 체제 버전입니다.
LSPCON: 7세대 Intel Core 프로세서에서 HDMI를 통한 HDR 신호를 활성화하려면 마더보드에 LSPCON(레벨 시프터 및 프로토콜 변환기)이라는 추가 하드웨어 구성 요소가 있어야 합니다. PC 제조업체가 설치해야 하는 구성요소이며 최종 사용자가 추가할 수 없습니다. LSPCON은 DisplayPort가 아닌 HDMI에서만 작동합니다. 9세대 Intel Core 프로세서 이상 HDMI2를 사용하는 최신 플랫폼에서는 2.0이 기본적으로 지원되므로 LSPCON 지원이 필요하지 않습니다.
LSPCON FW: LSPCON에는 올바른 버전의 FW가 필요합니다.
시스템 BIOS: 특히 Ultra HD Blu-ray 재생의 경우 Intel Software Guard Extensions(SGX)를 지원하도록 시스템 BIOS를 올바르게 구성해야 합니다.
인텔 CSME FW: 필요한 HW-DRM 지원을 구현하려면 인텔 관리 엔진(ME) 펌웨어 버전이 필요하며 HDCP2.2 고급 HDR 비디오 콘텐츠에는 일반적으로 시스템 제조업체가 소유한 시스템 BIOS에 포함된 링크 보호가 필요합니다.
Intel MEI 드라이버: 소프트웨어가 ME FW와 통신할 수 있도록 이 드라이버를 설치해야 합니다.
애플리케이션: HDR 콘텐츠를 재생하려면 특정 애플리케이션과 인터넷 브라우저(예: Microsoft Edge)가 필요합니다.
콘텐츠: HDR 비디오 파일은 다양한 소스에서 제공됩니다. Netflix와 같은 특정 스트리밍 공급자로부터 HDR 콘텐츠를 수신하려면 적절한 요금제/계정 유형이 있어야 합니다.
HDR 디스플레이: EDR(Extended Dynamic Range)이라는 부분 HDR 환경은 일부 장치의 내장 디스플레이에서 사용할 수 있지만 노트북 및 태블릿의 내장 디스플레이에서는 아직 진정한 HDR 재생을 사용할 수 없습니다.
디스플레이 커넥터: HDR 모니터에 연결된 컴퓨터의 물리적 디스플레이 인터페이스(인터페이스)는 HDMI, DisplayPort, 미니 DisplayPort 또는 USB Type-C일 수 있습니다. 모니터에 고급 컨텐츠를 제공하는 데 필요한 HDCP2.2 지원을 찾는 것이 중요합니다.
케이블/동글: 기본 HDMI 또는 DP 커넥터를 지원하는 PC의 경우 적절한 케이블을 사용하여 모니터에 직접 연결할 수 있습니다. PC에 USB Type-C 포트(Thunderbolt 3 또는 DP Alt 모드 지원)가 있는 경우 USB Type-C를 HDMI2.0 또는 DisplayPort로 변환하고 HDCP2를 지원하려면 어댑터나 동글이 필요합니다. miniDP 커넥터에도 유사한 어댑터가 필요합니다. 이러한 어댑터는 Club3D, BelkinUptab 등과 같은 타사 공급업체에서 구입할 수 있습니다.
또한 **Intel GMA(Graphics Media Accelerator)**는 Intel이 2004년에 출시한 통합 그래픽 프로세서 시리즈입니다. 초기 Intel Extreme Graphics 시리즈를 대체하고 Intel HD 및 Iris Graphics 시리즈로 대체되었습니다. 이 시리즈는 저가형 그래픽 솔루션 시장을 겨냥하고 있습니다. 이 제품군은 마더보드에 통합되어 있고 그래픽 처리 능력이 제한되어 있으며 전용 비디오 메모리가 아닌 컴퓨터의 메인 메모리를 저장용으로 사용합니다. 이는 넷북, 저가형 노트북, 데스크톱 컴퓨터는 물론 높은 수준의 그래픽 기능이 필요하지 않은 업무용 컴퓨터에서도 흔히 볼 수 있습니다. 2007년 초에는 PC 마더보드의 약 90%에 GPU가 통합되어 있었습니다.
16.4.4 퀄컴
Freedreno는 Qualcomm의 Adreno 그래픽 하드웨어용 완전 오픈 소스 드라이버를 구현하는 오픈 소스 리버스 엔지니어링 프로젝트입니다. Freedreno는 MSM DRM 드라이버, xf86 비디오 Freedreno DDX 및 Mesa의 내부 Freedreno Gallium3D 드라이버로 구성됩니다. 소스코드 주소는 https://github.com/freedreno/freedreno 입니다.
사용자 공간 구성 요소는 MSM DRM/KMS 커널 드라이버를 사용하거나 다운스트림 MSM Android 트리의 MSM FBdev+KGSL 드라이버를 사용하는 두 가지 모드로 실행될 수 있습니다. 이것의 주요 목적은 Android 장치에서 FreeDreno를 더 쉽게 사용할 수 있도록 하는 것입니다. 특히 MSM DRM/KMS 드라이버에는 휴대폰/태블릿의 LCD 디스플레이에 대한 완전한 DSI 패널 지원이 아직 없기 때문입니다. (MSM DRM/KMS에서 DSI 지원이 이루어지더라도 LCD 패널의 서로 다른 모델마다 패널 드라이버를 작성해야 합니다.)
DRM/KMS 드라이버를 사용할 때 그래픽 스택은 다른 오픈 소스 데스크탑 드라이버(Nouveau, Radeon 등)와 유사합니다.

android fbdev/kgsl 드라이버를 사용할 때 xf86 video freedreno의 fbmode_display 모드 설정 코드와 libdrm_freedreno의 kgsl 백엔드가 drmmode_display 및 msm 백엔드 대신 사용된다는 점을 제외하면 스택은 거의 동일합니다. 사용자 공간 구성 요소를 다시 컴파일하지 않고도 xf86 video freedreno 및 libdrm_freedreno는 런타임에 무엇을 사용할지 결정할 수 있습니다.

CP(명령 프로세서)는 링버퍼(PM4 명령 스트림)에서 일련의 렌더링 명령을 읽는 블록입니다. 일부 레지스터 값을 설정하거나 일부 렌더링 작업을 트리거할 수 있습니다. 주로 Type-0(PKT0) 및 Type-3(PKT3) 명령으로 구성됩니다. Type-0(PKT0)은 BASE_INDEX로 지정된 레지스터에서 시작하여 N개의 연속(32비트) DWORD를 N개의 레지스터에 씁니다(아래 그림의 왼쪽). Type-3(PKT3)은 IT_OPCODE opcode에 지정된 작업을 수행합니다(아래 그림의 오른쪽).

많은 임베디드/SoC GPU와 마찬가지로 Adreno는 타일 기반 아키텍처이지만 구현이 더 간단합니다. 대부분의 타일러는 작은(32x32 및/또는 64x64) 타일을 렌더링하며 하드웨어는 어떤 방식으로든 각 타일의 형상을 정렬하며 일반적으로 주어진 타일의 보이지 않는 표면을 무시합니다. 반면 Adreno는 크기가 256KB에서 1MB에 이르는 (상대적으로) 큰 인코어(GMEM) 또는 온칩(OCMEM) 청킹 버퍼를 가지고 있습니다. 렌더링되는 버퍼는 "타일" 또는 "빈"으로 나누어지며, 색상 버퍼와 (활성화된 경우) 깊이/스텐실 버퍼는 타일 버퍼에 수용될 수 있습니다. 드라이버는 각 타일/빈 그리기, 복구(시스템 메모리에서 GMEM으로 데이터 이동) 및 구문 분석(GMEM에서 시스템 메모리로 데이터 이동)을 전적으로 담당합니다. 구문 분석 단계는 여러 채널을 통한 다중 샘플 구문 분석에 사용될 수 있습니다.
가장 간단한 방법은 상태를 설정하고 지우기/그리기를 수행하고 타일을 무시하도록 CMD를 설정한 다음 최상위 명령 스트림 버퍼(커널에 제출된 것)에서 (선택적으로) 각 타일 세트, IB(분기)를 지우기/그리기 명령으로 구문 분석한 다음 다음을 구문 분석하는 것입니다.

각 타일 내의 렌더링 효과는 기존 IMR과 유사합니다.
타일별 명령:
복원 - 선택적으로 콘텐츠를 시스템 메모리에서 타일 버퍼로 전송합니다.
창 오프셋 및 화면 클리핑을 설정합니다.
IB 지우기/그리기 렌더링 명령.
구문 분석 - 타일 버퍼를 시스템 메모리로 전송합니다.
참고: 명령 스트림 구성 순서는 GPU 실행 순서와 다르며 지우기/그리기에도 사용되는 일부 GPU 상태 레지스터를 복원/분석하므로 첫 번째 지우기/그리기 전에 일부 상태 개체를 더티로 표시하려면 드라이버에서 주의를 기울여야 합니다.
위의 내용은 gallium3D 드라이버에서 구현된 내용이며 작은 양의 지오메트리 및/또는 저렴한 버텍스 셰이더가 있는 경우 반드시 큰 단점은 아닙니다.
위의 대략적인 접근 방식에는 버텍스 셰이더가 모든 저장소의 모든 정점에 대해 실행된다는 단점이 있지만 이를 두 개의 패스로 분할하여 오버헤드를 줄일 수 있습니다. 첫 번째 패스("비닝" 프로세스)에서는 정점이 각 bin으로 분할되고, 이 정보는 두 번째 패스에서 각 bin에 대해 처리되는 정점을 제한하는 데 사용됩니다. 두 패스 모두에서 동일한 버텍스 셰이더를 사용하는 대신 비닝 패스에서는 gl_Position/gl_PointSize만 계산하는 단순화된 셰이더를 사용할 수 있습니다.
참고: 다음 설명은 a3xx에 적용되지만 a2xx는 대체로 유사해야 합니다.
Blob 드라이버는 각 타일에 VSC_PIPE를 할당합니다. 총 8개의 파이프라인이 있습니다. 여러 타일을 하나의 파이프라인에 할당할 수 있습니다. 즉, 아래와 같이 4개의 파이프라인을 사용하여 4x4 타일을 배열할 수 있습니다.
## X, Y = upper-left tile coord of group of tiles mapped to pipe
## W, H = size of group in tiles, so below each pipe is mapped to
## a 2x2 group of tiles
VSC_PIPE[0].CONFIG: { X = 0 | Y = 0 | W = 2 | H = 2 }
VSC_PIPE[0x1].CONFIG: { X = 0 | Y = 2 | W = 2 | H = 2 }
VSC_PIPE[0x2].CONFIG: { X = 2 | Y = 0 | W = 2 | H = 2 }
VSC_PIPE[0x3].CONFIG: { X = 2 | Y = 2 | W = 2 | H = 2 }각 파이프라인에 대해 드라이버는 파이프라인 버퍼 주소/크기(VSC_PIPE[p].DATA_ADDRESS 및 VSC_PIPE[p].DATA_LENGTH)를 구성하여 가시성 흐름 데이터를 저장할 위치를 GPU에 제공합니다. 크기 버퍼(VSC_SIZE_ADDRESS)는 GPU가 각 파이프라인 버퍼에 기록된 데이터의 양을 저장하는 4바이트 x 8파이프라인 버퍼로, 비닝 중에 어떤 정점이 어떤 파이프라인에 저장되는지 제어하는 데 사용됩니다. 렌더링하는 동안 각 타일의 시작 부분에서 드라이버는 CP_SET_BIN_DATA 패킷을 통해 파이프라인 p(즉, 적절한 버퍼 크기/주소)의 데이터를 사용하도록 GPU를 구성합니다.
OUT_PKT3(ring, CP_SET_BIN_DATA, 2);
OUT_RELOC(ring, pipe[p].bo, 0); /* same value as VSC_PIPE[p].DATA_ADDRESS */
OUT_RELOC(ring, size_addr_bo, (p * 4)); /* same value as VSC_SIZE_ADDRESS + (p * 4) */
OUT_PKT0(ring, REG_A3XX_PC_VSTREAM_CONTROL, 1);
OUT_RING(ring, A3XX_PC_VSTREAM_CONTROL_SIZE(pipe[p].config.w * pipe[p].config.h) |
A3XX_PC_VSTREAM_CONTROL_N(n)); /* N is 0..(SIZE-1) */
OUT_PKT3(ring, CP_SET_BIN, 3);
OUT_RING(ring, 0x00000000);
OUT_RING(ring, CP_SET_BIN_1_X1(x1) | CP_SET_BIN_1_Y1(y1));
OUT_RING(ring, CP_SET_BIN_2_X2(x2) | CP_SET_BIN_2_Y2(y2));**대부분의/모든 청커와 마찬가지로 렌더 대상을 전환하면 비용이 많이 들고 새로 고침이 트리거됩니다.**또한 적어도 freedreno gallium3D 드라이버의 경우 버퍼의 일부만 렌더링하는 경우 버퍼에서 건드릴 수 없는(읽거나 쓸 수 있는) 부분을 클립하는 것이 좋습니다. Gallium 드라이버는 이 정보를 사용하여 타일 경계/크기를 조정하여 불필요한 복원(시스템 메모리에서 GMEM으로 데이터 가져오기) 또는 구문 분석(GMEM에서 다시 시스템 메모리로 데이터 쓰기)을 방지할 수 있습니다.
ISA(명령어 세트 아키텍처)와 관련하여 a2xx 셰이더 ISA와 달리 a3xx는 "간단한" 스칼라 명령 세트를 사용하지만 몇 가지 트릭이 있습니다. 컴파일러는 스케줄링 및 기타 제약 조건을 더 잘 알고 있어야 합니다. 각 명령은 64비트(qword)이며 7개의 기본 명령 인코딩 또는 "범주"(경우에 따라 여러 하위 인코딩)가 있습니다. a2xx와 마찬가지로 별도의 CF 대 FETCH/ALU 절차가 없습니다. 그러나 일부 명령어 클래스는 비동기식으로 실행되며 쓰기 전 읽기(또는 쓰기 전 읽기)를 처리하려면 특별한 동기화가 필요합니다. a2xx와 달리 이제 전체 및 절반(16비트) 레지스터가 있으며 어느 것도 겹치지 않습니다. 지침은 부동 소수점뿐만 아니라 정수에도 적용됩니다. 7가지 명령어 인코딩은 다음과 같습니다.
카테고리 0(cat0): 일반적으로 nop, 점프, 분기와 같은 인수가 없는 흐름 제어 명령(때로는 내장된 상수 포함)을 사용합니다.
범주 1(cat1): 이동/변환(단일 소스 레지스터)의 변형인 이 유형의 명령어에는 opcode가 없지만 셰이더 니모닉은 src 및 대상 유형에 따라 다릅니다. src와 대상 유형이 동일한 경우 이를 이동이라고 합니다.
mov.f16f16 Rdst, Rsrc - 동일한 유형의 src 및 dst에서 이동합니다.
cov.f32u16 Rdst, Rsrc - f32 src에서 u16 dst로 이동/변환합니다.
mova - mov.f16f16은 레지스터(a0)로 주소가 지정됩니다. (모든 경우에 src 레지스터는 const일 수 있습니다)
카테고리 2(cat2): 일반 ALU 명령어, 일반적으로 2개의 src 레지스터가 있지만 일부 경우에는 두 번째 src 인코딩이 무시됩니다.
add.f Rdst, Rsrc0, Rsrc1
및.b Rdst, Rsrc0, Rsrc1
Floor.f Rdst, Rsrc0 - 두 번째 src를 무시하는 cat2의 예입니다.
카테고리 3(cat3): 3개의 src 레지스터 작업, 예:
mad.f16 - src0 * src1 + src2
sel.f32 - src1 ? src0 : src2
범주 4(cat4): 복잡한 단일 src 작업에는 더 많은 주기(잠재적으로 예측할 수 없는 수)가 필요하거나 cat1-cat3보다 더 비동기적입니다.
rcp Rdst, Rsrc
- log2 Rdst, Rsrc
cat4 명령어로 작성된 레지스터에서 읽는 기타 비cat4 명령어에는 복잡한 alu 파이프라인과 동기화하도록 설정된 (ss) 비트가 있어야 합니다.
- 카테고리 5(cat5): 일반 텍스처 샘플 관련 지침:
샘(f32)(xyzw)Rdst, Rsrc0, Rsrc1, s#0, t#0
isam (f32)(xyzw)Rdst, Rsrc0, Rsrc1, s#0, t#0
samgq (f32)(xyzw)Rdst, Rsrc0, Rsrc1, s#0, t#0
isam (f32)(xyzw)Rdst, Rsrc0, Rsrc1, Rsrc2
카테고리 6(cat6): 개인/로컬/전역 메모리에 대한 로드/저장 명령, 원자 추가/구독/스왑 등 및 기타 기타 명령. OpenCL에 가장 유용합니다.
스케줄링에서 컴파일러는 이전 명령어의 대상 레지스터가 준비되기 전에 (명령어 스케줄링) 주기 수를 고려해야 합니다. cat1-cat3 명령어의 경우 대상 레지스터는 3개의 명령어 이후에 사용할 수 있으며 컴파일러는 필요한 경우 nop 명령어를 삽입하는 역할을 담당합니다. cat4 또는 cat5 명령어로 작성된 대상 레지스터의 경우 (ss) 또는 (sy) 비트를 동기화용으로 설정할 수 있습니다. cat1-cat3과 달리 완료하는 데 필요한 사이클 수를 예측할 수 없기 때문입니다. 특히 cat3 명령어의 경우 세 번째 src 레지스터는 두 번째 사이클까지 필요하지 않으므로 DP4(내적)와 같은 명령어는 다음과 같이 구현될 수 있습니다.
; DP4 r0.x, r2.xyzw, r3.xyzw:
mul.f r0.x, r2.x, r3.x
nop
mad.f32 r0.x, r2.y, r3.y, r0.x
nop
mad.f32 r0.x, r2.z, r3.z, r0.x
nop
mad.f32 r0.x, r2.w, r3.w, r0.x이전 명령어의 결과를 얻기 위해 두 개의 nop를 요구하는 대신 컴파일러는 가능하다면 이러한 nop 슬롯에 관련 없는 명령어를 예약할 수 있습니다. 레지스터에 쓰기 위한 명령어는 텍스처 샘플 명령어의 src(WAR 위험)였으며 (ss) 비트 세트가 필요했습니다.
일반적으로 간단한 if/else 구성은 전개되어 분기의 모든 분기를 실행한 다음 sel 명령을 사용하여 흐름 제어 관점에서 "가져온" 분기의 결과를 조건부로 다시 작성합니다. 스레드 간 발산 흐름 제어는 일반적으로 비용이 많이 들기 때문에(즉, 하드웨어는 결국 스레드 그룹에서 한 번에 하나의 스레드를 실행해야 하므로) 컴파일러는 일반적으로 이를 피하려고 합니다. (현재 if/else는 Gallium 드라이버의 분기로 구현됩니다. 단순히 컴파일러가 그것을 풀기 방법을 알 만큼 똑똑하지 않기 때문입니다.) 분기가 필요할 때 cat0 명령어를 사용하여 구현할 수 있습니다. 예를 들어 if/else는 다음과 같은 방식으로 구현할 수 있습니다.
cmps.f.eq p0.x, hr1.x, hc2.x
br p0.x, #6
mov.f16f16 hr1.x, hc2.x
mov.f16f16 hr1.y, hc2.y
mov.f16f16 hr1.z, hc2.x
mov.f16f16 hr1.w, hc2.y
jump #6
(jp)nop
mov.f16f16 hr1.x, hc2.y
mov.f16f16 hr1.y, hc2.x
mov.f16f16 hr1.z, hc2.x
mov.f16f16 hr1.w, hc2.y
(jp)nop(jp)(점프 대상) 플래그는 분기 대상 명령에 설정되어 스레드 스케줄러가 잠재적인 랑데부 지점을 파악하는 데 도움이 될 수 있습니다. 점프 대상이 반드시 놉일 필요는 없습니다. 분기는 즉시 앞으로(양수) 또는 뒤로(음수) 오프셋될 수 있습니다.
그룹화된 채널이 종료된 후에는 더 이상 삽입하거나 삭제하라는 명령이 없습니다. 각 기본 블록은 깊이 패스에 의해 생성된 깊이 순서 목록의 가장 깊은 노드에서 시작하여 소스 명령어와 지연 슬롯 뒤에 각 명령어를 재귀적으로 예약하고 필요에 따라 NOP를 삽입하도록 예약됩니다.
지시문에서 const src 매개변수를 사용하는 데는 몇 가지 제한 사항이 있으며 경우에 따라 컴파일러는 const를 GPR로 이동해야 합니다. 알려진 제한 사항은 다음과 같습니다.
cat2는 최대 하나의 상수 src를 사용할 수 있습니다(그러나 어디에서나).
cat3은 상수 src를 두 번째 매개변수(src1)로 사용할 수 없습니다.
cat4는 상수 src를 허용할 수 없습니다.
16.4.5 기타
또한 다른 플랫폼용 드라이버도 있습니다.
Vidix: 사용자 공간에서 실행되는 비디오 카드 드라이버가 X Window System의 Direct Graphics Access 확장을 통해 프레임 버퍼에 직접 액세스할 수 있도록 하는 Unix 계열 운영 체제용 휴대용 프로그래밍 인터페이스입니다.
MPLAB: MPLAB Harmony Graphics Suite는 32비트 마이크로칩 장치용 임베디드 그래픽 펌웨어 솔루션을 만들기 위한 MPLAB 에코시스템의 확장입니다.

- MiniGLX: X 윈도우 시스템이 없는 Linux 또는 윈도우 시스템이 없는 임베디드 시스템과 같이 윈도우 시스템이 없는 시스템에서 OpenGL 렌더링을 용이하게 하는 애플리케이션 프로그래밍 인터페이스 사양입니다. 이 인터페이스는 GLX 인터페이스의 하위 집합이며 Xlib와 유사한 기능의 최소 집합입니다.
16.5 그래픽 기반 애플리케이션
16.5.1 비디오 및 합성
GFX/비디오 재생 사용 사례(애플리케이션의 비디오 스트리밍 유형)를 실행할 때 Intel 아키텍처에서 UI 경험에 영향을 미치는 특정 안정성 문제를 살펴보면, 동작은 UI가 정지되고 검은 화면이 나타난 다음 시스템이 다시 시작되는 것입니다(물론 임의의 시간 간격 후).
3D 클라이언트 응용 프로그램이 GPU를 "멈추면" GPU 프로세스가 종료되고 GPU가 완전히 재설정될 수 있습니다. 비디오 디코딩과 같은 복잡한 사용 사례의 경우 현재 많은 프레임/객체가 실행 중이므로 GPU 프로세스를 종료하고 GPU를 재설정하면 바람직하지 않은 효과가 발생할 수 있습니다.

권장 솔루션: 시간 초과 감지 및 복구(TDR). 애플리케이션이 단일 배치 버퍼에서 정지 감지를 활성화하여 안정성과 견고성을 향상시킬 수 있도록 하는 Intel GPU(wip으로 업스트림됨)를 위한 새로운 기능입니다. TDR(시간 초과 감지 및 복구)을 사용하면 GPU의 여러 엔진을 독립적으로 재설정할 수 있습니다(GPU를 완전히 재설정하는 대신). 일반적으로 이러한 구현에서는 i915 드라이버에 새로운 IRQ 핸들러와 GPU의 링 버퍼에서 발행된 배치 버퍼의 시작 명령 전후에 두 개의 새로운 GPU 명령 명령이 도입됩니다. TDR의 단계는 다음과 같습니다.

제안된 솔루션:
UMD 미디어 드라이버는 배치 버퍼를 보낸 후 타이머를 시작합니다.
타이머가 만료된 후 미디어 엔진이 일시 중지된 상태인 것으로 감지됩니다.
GPU 드라이버는 영향을 받는 미디어 엔진만 재설정합니다.
UMD 미디어 드라이버는 잘못된 배치가 제출된 시기를 알고 있으므로 미디어 드라이버가 재설정에서 복구하는 데 걸리는 시간 동안 조치를 취할 수 있습니다.

전체 메커니즘은 ioctl을 통해 애플리케이션에서 설정할 수 있는 임의의 임계값을 통해 작동합니다. 그러나 임계값이 너무 낮아서는 안 됩니다. 그렇지 않으면 너무 많은 오탐지가 생성됩니다.
합성자는 어떤 이점을 얻나요? 아래 다이어그램을 사용하여 대답하십시오.
신디사이저의 기본 작업은 프레임을 생성하는 것입니다.
과거에는 GPU 정지를 감지하면 컴포지터가 너무 늦게 재개되었습니다(화면 정지, 녹색 또는 검은색 화면 또는 시스템 다시 시작).
이제 비디오 클라이언트 애플리케이션은 "작업"으로 인해 미디어 엔진이 충돌하는지 여부를 조기에 판단할 수 있으며, 그렇다면 미디어 엔진이 재설정에서 반환되는 동안 컴포지터에 플래그를 지정하여 현재 프레임을 표시할 수 있습니다.

16.5.2 견고한
Rocksolid는 GPU 벤치마크 제품의 엔진으로 시작하여 나중에 독립형 제품으로 발전했습니다. 고객 요구 사항 외에도 개발은 기본 개발과 밀접하게 연결되어 있습니다. 주로 게임 이외의 용도를 대상으로 하는 경량 렌더링/컴퓨팅 엔진으로, 소형 임베디드 시스템에서 최신 데스크탑급 하드웨어까지 확장됩니다. 본격적인 게임 엔진은 아니지만 현대의 대형 게임 엔진에 비해 오버헤드가 훨씬 낮고 사용자 정의가 더 쉽고 안정적이며 보안 인증을 통과할 수 있습니다. 다음 그림은 Rocksolid 엔진의 아키텍처 다이어그램입니다. 성능 향상을 위해 장치 드라이버에 직접 접근할 수 있음을 알 수 있다.

그래픽 파이프라인은 이미지 처리와 같은 작업을 실행하는 좋은 방법입니다. 많은 하드웨어에서 문제가 자연스럽게 전체 화면 래스터라이제이션 프로세스에 매핑되는 경우 계산 파이프라인보다는 그래픽 파이프라인으로 실행하는 것이 더 빠릅니다. 한 산업 고객 사례에서 Rocksolid는 GPU 가속 이미지 처리 파이프라인을 제공하는 데 사용되었습니다. 대상 하드웨어는 원래 OpenCL 버전에 비해 몇 배 더 빠릅니다.
OpenGL에서 Rocksolid 엔진은 기록된 노드 명령 목록을 토폴로지 정렬로 실행합니다. Vulkan에는 사용된 각 명령 대기열에 대한 제출 스레드가 있습니다. 현재 기본 설정은 명령 대기열이므로 제출 스레드가 하나만 있습니다. 제출 스레드는 지속적으로 실행됩니다. 제출 스레드가 여전히 명령을 푸시하는 동안 프로그램의 나머지 부분은 다음 프레임을 준비할 수 있습니다. Vulkan의 CPU 표시 리소스는 간단한 루프 펜스 시스템으로 보호됩니다.
16.5.3 I/O 드라이버
애플리케이션의 입출력 요청을 장치에 대한 하위 수준 명령으로 변환하여 장치 컨트롤러로 보내고, 입출력 장치로부터 응답을 얻어 애플리케이션으로 보냅니다.

입/출력 시스템의 레이어와 각 레이어의 주요 기능.
하드웨어에서 IO에 액세스하는 방법은 무엇입니까? 단계는 다음과 같습니다:
운영체제는 입출력을 완료하기 위해 장치 컨트롤러에 명령과 제어를 주고 받아야 합니다.
장치 컨트롤러에는 제어 및 데이터를 위한 하나 이상의 레지스터가 있습니다.
프로세서는 이러한 레지스터를 읽고 쓰면서 컨트롤러와 통신합니다.
이 레지스터의 주소를 지정하는 방법은 무엇입니까?
메모리 기반 I/O.
포트 기반 입출력.
입출력이 혼합되어 있습니다.
메모리 매핑/포트 기반/혼합 IO 방법은 다음과 같습니다.

(a) 특수 CPU 명령(입력/출력). (b) 메모리 매핑: 하드웨어 입출력 레지스터를 위한 메모리 영역을 예약합니다. 표준 메모리 명령어가 이를 업데이트합니다. (c) 혼합: 일부 컨트롤러는 메모리에 매핑되고 일부는 I/O 명령을 사용합니다.

단일 버스 및 듀얼 버스 IO. (a) 메모리 매핑 I/O에는 주소 공간이 하나만 있으며, 메모리 매핑 I/O는 구현 및 사용이 더 쉽습니다. 메모리 매핑 I/O에는 프레임 버퍼 또는 유사한 장치가 더 적합합니다. (b) 포트 기반 I/O에는 두 개의 주소 공간이 있습니다. 하나는 메모리용이고 다른 하나는 포트용입니다. 듀얼 버스를 사용하면 데이터와 장치의 병렬 읽기/쓰기가 가능합니다.
단일 버스와 이중 버스의 보다 자세한 비교 차트는 다음과 같습니다.


버스: 여러 장치를 연결할 수 있는 구성 요소(CPU 포함) 간의 상호 연결입니다.

포트: 하나의 입력/출력 장치만 연결되는 인터페이스입니다.

장치 컨트롤러: 물리적 장치를 시스템 버스/포트에 연결합니다.

각 장치에는 운영 체제와 통신하기 위한 장치 컨트롤러와 장치 드라이버가 있습니다. 장치 드라이버는 특정 장치를 처리하기 위해 운영 체제에 연결할 수 있는 소프트웨어 모듈입니다. 장치 컨트롤러는 장치와 장치 드라이버 간의 인터페이스 역할을 합니다. 장치 컨트롤러는 여러 장치를 처리할 수 있습니다. 인터페이스로서 주요 작업은 직렬 비트 스트림을 바이트 블록으로 변환하고 필요에 따라 오류 수정을 수행하는 것입니다.

IO 포트 레지스터에는 상태 레지스터(호스트가 읽음), 명령 레지스터(호스트가 기록함), 레지스터의 데이터(입력을 얻기 위해 호스트가 읽음) 및 데이터 출력 레지스터(출력을 보내기 위해 호스트가 기록함)가 포함됩니다.

직접 메모리 액세스(DMA): 디스크 드라이브와 같이 대규모 전송을 수행하는 장치의 경우 고가의 범용 프로세서를 사용하여 한 번에 1바이트씩 컨트롤러 레지스터에 대한 상태 비트 및 입력 데이터를 모니터링하는 것은 낭비적인 것으로 보입니다. 이 프로세스를 입/출력 프로그래밍이라고 합니다. 인터럽트 기반 I/O는 모든 바이트가 인터럽트 핸들러 루틴에 대한 컨텍스트 전환을 생성하기 때문에 해결책이 아닙니다. 폴 기반 및 인터럽트 기반 I/O에서는 모든 바이트가 CPU를 통과해야 하며, 입출력 장치<->CPU<->메모리에 대한 오버헤드가 많이 발생합니다. 이 일상적인 작업을 입/출력 장치의 데이터를 직접 메모리로 이동할 수 있는 특수 목적 프로세서로 오프로드할 수 있다면 정말 좋을 것입니다! 이는 직접 메모리 액세스(DMA) 컨트롤러입니다.
DMA 전송을 시작하기 위해 호스트는 DMA 명령 블록을 메모리에 씁니다. 전송 소스에 대한 포인터, 전송 대상에 대한 포인터 및 전송할 바이트 수입니다. CPU는 이 명령 블록의 주소를 DMA 컨트롤러에 쓴 다음 다른 작업을 계속합니다. DMA 컨트롤러는 계속해서 메모리 버스를 직접 작동하여 메인 CPU의 도움 없이 버스에 주소를 배치하여 전송을 수행합니다. 단순 DMA 컨트롤러는 PC의 표준 구성 요소이며 PC의 버스 마스터 입력/출력 보드에는 일반적으로 자체 고속 DMA 하드웨어가 포함되어 있습니다. DMA를 사용한 IO 예:
/* Code executed when the print system call is made */
copyFromUser(buffer, p, count);
setupDMAController();
scheduler();
/* Interrupt Service Routine Procedure for the printer */
acknowledgeInterrupt();
unblockUser();
returnFromInterrupt();인터럽트는 바이트당 한 번이 아니라 I/O 작업당 한 번 생성됩니다(인터럽트 기반 I/O의 경우).
IO 하드웨어 인터페이스: 장치 드라이버는 디스크 데이터를 주소 X의 버퍼로 전송하라는 지시를 받습니다. 장치 드라이버는 디스크 컨트롤러에게 디스크에서 주소의 버퍼로 C 바이트를 전송하라고 지시합니다.

애플리케이션 IO 인터페이스는 아래 그림에 나와 있습니다.

컴퓨터에 연결된 모든 입력/출력 장치를 제어하려면 장치별 코드가 필요합니다. 각 운영 체제에는 장치 제조업체가 작성한 자체 장치 드라이버가 필요하며 각 장치 드라이버는 특정 유형 또는 클래스의 입/출력 장치를 지원합니다. 마우스 드라이버는 다양한 유형의 마우스를 지원할 수 있지만 웹캠은 지원하지 않습니다. 운영 체제는 드라이버의 기능과 드라이버가 운영 체제의 나머지 부분과 상호 작용하는 방식을 정의합니다. 장치 드라이버에는 상위의 장치 독립적인 소프트웨어로부터 추상적인 읽기 및 쓰기 요청을 수락하고 이러한 요청이 실행되도록 보장하고 장치 초기화, 전원 요구 사항 관리 및 이벤트 로깅 등 여러 기능이 있습니다.
Microsoft Windows는 파일 시스템의 장치 바로 가기를 사용하여 장치 주소를 지정하고, 장치 액세스 API는 응용 프로그램 프로그래머가 장치를 검사하고 상호 작용할 수 있는 인터페이스를 제공하며, Windows 장치 프레임워크는 장치 드라이버 개발을 위한 사용자 및 커널 인터페이스를 제공합니다. 입력/출력 범주(운영 체제 관점)는 다음과 같습니다.
문자 스트림 및 블록.
순차 액세스와 무작위 액세스. 장치 드라이버를 사용하면 장치에서 오프셋을 찾을 수 있습니다.
동기식 및 비동기식. 장치 드라이버의 I/O 작업은 장치 컨트롤러의 I/O와 동기적으로 완료되며, 비동기 I/O는 더 일찍 반환되고 나중에 성공/실패를 보고합니다.
버퍼링되고 직접적입니다. 작업 결과 보고는 버퍼 또는 장치 컨트롤러에서 수행됩니다.
공유 또는 전용. 각 장치 인스턴스의 I/O는 상호 배타적입니다. (예: 프린터)
읽기 전용, 쓰기 전용, 읽기 및 쓰기.
커널은 하드웨어 및 장치 드라이버 인프라를 기반으로 스케줄링, 버퍼링, 캐싱, 풀링, 장치 예약, 오류 처리 등 다양한 I/O 관련 서비스를 제공합니다.
IO 스케줄링은 일련의 I/O 요청을 예약하는 데 사용됩니다. 이는 요청을 실행할 올바른 순서를 결정하는 것을 의미합니다. 운영 체제 개발자는 각 장치에 대한 요청 대기열을 유지하여 예약을 구현합니다. 애플리케이션이 차단 I/O 시스템 호출을 발행하면 해당 요청이 해당 장치의 대기열에 배치됩니다. I/O 스케줄러는 대기열 순서를 재정렬하여 전체 시스템 효율성과 평균 애플리케이션 응답 시간을 향상시킵니다. 입력/출력은 느린 경우가 많으며 하드 드라이브와 같은 일부 장치의 물리적 특성(헤드의 움직임과 회전으로 인해 발생하는 메커니즘 및 대기 시간)을 최적화해야 합니다. FIFO 전략으로 입출력을 수행하는 경우 기계적 지그재그 동작이 입출력 동작을 무시할 수 있습니다. I/O 스케줄러는 장치에서 일련의 I/O 요청을 받아 장치에서 요청을 실행하는 데 가장 적합한 순서와 시간을 결정합니다. 여러 작업이 I/O 요청을 처리하기 위해 경쟁하면 일정이 복잡해집니다.
블록 장치 작업은 가상 메모리 및 페이징과 긴밀하게 연결되어 있으며 일부 프레임은 페이지 캐시로 사용되고 블록 장치의 데이터를 시스템에 유지합니다. 블록 장치의 입/출력: 블록이 이미 페이지 캐시(물리적 메모리)에 있는지 검색합니다. 기존 프레임에 대한 읽기/쓰기 버퍼가 발견되면 그렇지 않으면 프레임을 할당하고 장치 블록을 프레임으로 읽고 프레임을 캐시된 장치 블록 쌍으로 표시하고 이 프레임에서 버퍼를 읽고 씁니다. 더티 페이지가 블록 장치에 정기적으로 기록되어 I/O 작업, 특히 파일 시스템 메타데이터 작업 속도가 크게 향상됩니다.
페이지 캐시 아이디어는 메모리 매핑된 I/O와도 결합되며 mmap() 파일은 유사한 메커니즘을 사용합니다. 프로세스의 가상 메모리 맵 페이지는 블록 장치가 아닌 파일로 백업되고, 변경 사항은 메모리에서 업데이트되며, 캐시된 프레임은 디스크에 주기적으로 적용됩니다. VM 시스템은 페이지 및 파일 캐시는 물론 다른(상주 및 무료) 페이지에 대한 프레임을 추적하고, VM 시스템은 시스템의 메모리 상태에 따라 파일 및 장치 캐시의 크기를 조정합니다.
버퍼(Buffer)란 두 장치 간 또는 장치와 애플리케이션 간에 데이터를 전송할 때 데이터가 저장되는 저장 영역이다. 버퍼링에는 세 가지 이유가 있습니다.
- 데이터 스트림을 처리하는 생산자와 소비자 간의 속도 불일치. 하드 드라이브에 저장하기 위해 어댑터를 통해 파일을 수신합니다.

(a) 버퍼링되지 않은 입력. (b) 사용자 공간의 버퍼링. (c) 커널에 버퍼링되어 사용자 공간에 복사됩니다. (d) 커널의 이중 버퍼링.
- 데이터 전송 크기가 다른 장치 간에 조정합니다. 네트워크: 메시지는 일반적으로 전송 및 수신 중에 분할됩니다.

네트워킹에는 패킷의 여러 복사본이 포함될 수 있습니다.
- 애플리케이션 I/O에 대한 복제 의미 체계를 지원합니다. 애플리케이션은 write() 시스템 호출을 호출하여 버퍼에 대한 포인터와 쓸 바이트 수를 지정하는 정수를 제공합니다. 시스템 호출이 반환된 후 애플리케이션이 버퍼의 내용을 변경하면 어떻게 되나요? write() 시스템 호출을 처리할 때 운영 체제는 애플리케이션에 제어권을 반환하기 전에 애플리케이션 데이터를 커널 버퍼에 복사합니다. 디스크 쓰기는 커널 버퍼에서 수행되므로 애플리케이션 버퍼에 대한 후속 변경 사항은 영향을 미치지 않습니다.
캐싱은 I/O 효율성을 높이기 위해 I/O 수준에서 수행됩니다. 버퍼와 캐시의 차이점은 버퍼는 데이터 항목의 기존 복사본만 보유할 수 있는 반면, 캐시는 정의에 따라 다른 곳에 있는 항목의 더 빠른 저장소에 대한 복사본만 보유한다는 것입니다. 캐싱과 버퍼링은 서로 다른 기능이지만 때로는 메모리 영역을 두 가지 목적으로 모두 사용할 수 있습니다. 예를 들어, 복사 의미를 유지하고 디스크 I/O의 효율적인 예약을 가능하게 하기 위해 운영 체제는 주 메모리의 버퍼를 사용하여 디스크 데이터를 보관합니다.
입력/출력 소프트웨어는 일반적으로 4개의 계층으로 나누어지며 각 계층에는 잘 정의된 인터페이스가 있습니다.

다음은 표준 드라이버 인터페이스가 있는 경우(오른쪽)와 없는 경우(왼쪽)의 비교 차트입니다.

16.5.4 UE 그래픽 드라이버
원칙적으로 애플리케이션 계층은 드라이버 계층과 GPU의 세부 사항에 신경 쓰지 않아야 하지만 이는 종종 역효과를 낳습니다. 수많은 GPU, 시스템, 그래픽 API 및 버전은 수많은 드라이버 버전을 생성하며, 이들 사이에는 몇 가지 이상한 문제가 있을 수 있습니다. 운전자는 공급망이 길고 문제 해결 주기가 긴 경우가 많습니다. 애플리케이션 개발자로서 가만히 앉아서 문제가 발생할 때까지 기다릴 수는 없습니다. 이를 해결하거나 방지하려면 먼저 주도권을 잡아야 합니다.
수년 전 한 블로거가 직장에서 이상한 버그를 발견했다는 사실이 생각납니다. 특정 GPU 브랜드의 특정 드라이버 버전에서 샘플링한 텍스처 색상에 문제가 있었습니다. 나중에 일주일 동안 열심히 디버깅한 후에 해당 드라이버 버전에서 구현된 Texture.sample의 좌표가 텍셀 중심으로 오프셋되지 않아 LUT 텍스처 색상에 큰 편차가 발생한다는 사실을 발견했습니다. 해결책도 매우 간단합니다. 해당 드라이버 버전에 맞게 Texture.sample의 셰이더 코드를 사용자 정의하면 됩니다.
UE는 제한된 인터페이스와 유형을 제공하여 GPU 또는 드라이버 정보를 읽을 수 있도록 일부 정보를 제공합니다. 관련 주요 인터페이스:
// GenericPlatformDriver.h
//
struct FGPUDriverInfo
{
uint32 VendorId; // DirectXID,0만약 설정(Set),을(를) 활용하여 로써 함수 설정(Set)/페치/가져오기(Fetch)
FString DeviceDescription; // e.g. "NVIDIA GeForce GTX 680" or "AMD Radeon R9 200 / HD 7900 Series"
FString ProviderName; // e.g. "NVIDIA" or "Advanced Micro Devices, Inc."
FString InternalDriverVersion; // e.g. "15.200.1062.1004"(AMD), "9.18.13.4788"(NVIDIA)
FString UserDriverVersion; // e.g. "Catalyst 15.7.1"(AMD) or "Crimson 15.7.1"(AMD) or "347.88"(NVIDIA)
FString DriverDate; // e.g. 3-13-2015
FString RHIName; // e.g. D3D11, D3D12
FGPUDriverInfo();
bool IsValid() const;
FString GetUnifiedDriverVersion() const;
bool IsAMD() const { return VendorId == 0x1002; }
bool IsIntel() const { return VendorId == 0x8086; }
bool IsNVIDIA() const { return VendorId == 0x10DE; }
(...)
};
// GPU정보
struct FGPUHardware
{
// 정보
const FGPUDriverInfo DriverInfo;
FGPUHardware(const FGPUDriverInfo InDriverInfo);
FString GetSuggestedDriverVersion(const FString& InRHIName) const;
FBlackListEntry FindDriverBlacklistEntry() const;
bool IsLatestBlacklisted() const;
const TCHAR* GetVendorSectionName() const;
(...)
};
// GenericPlatformMisc.h
struct CORE_API FGenericPlatformMisc
{
// 페치/가져오기(Fetch)GPU정보
static struct FGPUDriverInfo GetGPUDriverInfo(const FString& DeviceDescription);
(...)
};위의 인터페이스를 사용하면 렌더링 레이어와 게임 로직 레이어에서 드라이버 정보를 쉽게 얻어 목표 작업을 수행할 수 있습니다.
GPU 드라이버 외에도 Android Vulkan과 같은 다양한 그래픽 API의 RHI 구현에 자주 나타나는 그래픽 API 드라이버에 액세스할 수도 있습니다.
// AndroidPlatformMisc.cpp
bool FAndroidMisc::HasVulkanDriverSupport()
{
(...)
// this version does not check for VulkanRHI or disabled by cvars!
if (VulkanSupport == EDeviceVulkanSupportStatus::Uninitialized)
{
// assume no
VulkanSupport = EDeviceVulkanSupportStatus::NotSupported;
VulkanVersionString = TEXT("0.0.0");
// check for libvulkan.so
void* VulkanLib = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
if (VulkanLib != nullptr)
{
UE_LOG(LogAndroid, Log, TEXT("Vulkan library detected, checking for available driver"));
// if Nougat, we can check the Vulkan version
if (FAndroidMisc::GetAndroidBuildVersion() >= 24)
{
extern int32 AndroidThunkCpp_GetMetaDataInt(const FString& Key);
int32 VulkanVersion = AndroidThunkCpp_GetMetaDataInt(TEXT("android.hardware.vulkan.version"));
if (VulkanVersion >= UE_VK_API_VERSION)
{
// final check, try initializing the instance
VulkanSupport = AttemptVulkanInit(VulkanLib);
}
}
else
{
// otherwise, we need to try initializing the instance
VulkanSupport = AttemptVulkanInit(VulkanLib);
}
dlclose(VulkanLib);
if (VulkanSupport == EDeviceVulkanSupportStatus::Supported)
{
UE_LOG(LogAndroid, Log, TEXT("VulkanRHI is available, Vulkan capable device detected."));
return true;
}
else
{
UE_LOG(LogAndroid, Log, TEXT("Vulkan driver NOT available."));
}
}
else
{
UE_LOG(LogAndroid, Log, TEXT("Vulkan library NOT detected."));
}
}
return VulkanSupport == EDeviceVulkanSupportStatus::Supported;
}16.6 이 기사 요약
이 문서에서는 개념, 기술, 아키텍처, 메커니즘 및 관련 하드웨어 구성 요소를 포함하여 그래픽 렌더링 시스템의 드라이버 부분을 주로 설명합니다.
PC에서 개발자는 사용자에게 드라이버 업데이트를 요청할 수 있는데 이는 상대적으로 쉽습니다. 모바일 장치의 경우 드라이버는 여러 단계에서 인증을 받아야 하며 하드웨어 공급업체에서 고객까지의 연결 고리가 깁니다. 그렇게 하는 것은 비용이 많이 들고 느리며, 버그 수정과 새로운 기능은 몇 달이 걸릴 수 있습니다. 즉, 버그 수정이 사용자의 손에 도달하는 데 오랜 시간이 걸릴 수 있습니다. 구형/저사양 장치에서는 결코 도착하지 않을 수 있습니다. 이를 개선하기 위한 지속적인 노력이 있지만 드라이버 오류가 발견되면 업계 실무자가 이를 수정할 준비가 되어 있습니다. 상황은 (그러나 천천히) 개선되고 있습니다.
드라이버 버그에 대해 말하자면, 모바일 장치에서 Vulkan 드라이버를 작업하는 팀은 일반적으로 PC만큼 크지 않으며 테스트할 내장형 GPU 변형이 많이 있습니다. 이는 드라이버의 품질이 약간 뒤떨어지는 경우가 많다는 것을 의미합니다. 여기에 수정 사항이 작동하는지 확인하거나 다른 문제가 발생하는지 확인하기 위해 수정 사항을 릴리스하는 데 지연이 추가되며, 드라이버 품질이 문제가 되는 것은 놀라운 일이 아닙니다. 규정 준수 테스트가 향상됨에 따라 드라이버 테스트도 향상되고 있으며 Khronos의 하드웨어 공급업체는 이것이 최우선 사항이라는 점을 매우 분명하게 인식하고 있습니다. 업계 실무자들이 함께 모여 이를 개선해야 합니다(CTS).
최신 그래픽 API의 출현으로 드라이버는 더 이상 암시적 최적화를 수행하지 않으며 성능도 예상대로 낮습니다! 새 API를 사용하여 새 프로젝트를 시작하는 개발자에게는 이점이 있습니다(아래). 새로운 그래픽 API는 대규모 소프트웨어 설치에 더 많은 문제를 야기합니다. 올바른 순서로 필요한 정보를 얻을 수 있도록 렌더 흐름을 구성하는 것은 처음에는 개조하는 것보다 훨씬 쉽습니다. 또한 이전 API에서 수행한 드라이버 최적화를 기반으로 엔진을 작성하여 좋은 성능을 얻을 수 있습니다. 이제 소프트웨어 개발자는 성능을 예측 가능하게 만들고 올바른 최적화가 적용되도록 제어할 수 있습니다. 그러나 이는 이러한 최적화가 존재하는지 확인하는 것이 개발자의 몫임을 의미합니다.
img
img
DirectX11 드라이버(상단)와 DirectX12 애플리케이션(하단)으로 수행되는 작업 비교.
특별 지침
모든 참고문헌의 저자에게 감사드립니다. 일부 사진은 참고 자료와 인터넷에서 가져온 것이므로 삭제되었습니다.
이 시리즈의 기사는 저자가 직접 작성한 것이며 블로그에만 게시됩니다. 이 글의 링크를 공유하셔도 좋지만 무단 전재는 허용되지 않습니다!
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
📚 참고 자료 및 공식 링크 (References)
- Unreal Engine Source
- Rendering and Graphics
- Materials
- Graphics Programming
- Understanding Modern Device Drivers
- AMD GRAPHICS CORES NEXT (GCN) ARCHITECTURE
- I/O systems
- A low latency GPU engine based reset mechanism for a more robust UI experience
- Graphics Driver Quality - AMD
- High Dynamic Range(HDR)on Intel Graphics
- Understanding the Windows 8 graphics driver model
- Linux Graphics Drivers: an Introduction
- Linux GPU Driver Developer’s Guide
- Matrox Display Driver Guide
- nouveau Development
- envytools
- Mobile Graphics 101 - Arm Community
- Understanding Citrix HDX Graphics
- Windows Kernel Graphics Driver Attack Surface
- Vulkan in Rocksolid
- Windows Graphics Architecture
- Anatomy of RAM
- Memory structure
- FIFO overview
- NVIDIA TURING GPU ARCHITECTURE
- NVIDIA AMPERE GA102 GPU ARCHITECTURE
- 📖 GPU 하드웨어 아키텍처 및 작동 메커니즘에 대한 심층적인 이해
- Graphic Stack Overview
- The State of Linux Graphics
- A deeper look into GPUs and the Linux Graphics Stack
- Device driver
- Free and open-source graphics device driver
- Mesa (computer graphics)
- nouveau (software)
- AMD Radeon Software
- Freedreno in freedesktop
- Freedreno Architecture Overview
- Freedreno in Mesa3d
- Freedreno in Phoronix
- Freedreno in GitHub
- Adreno tiling
- Vidix
- Graphics card
- NVIDIA Linux Open GPU Kernel Module Source
- MPLAB® Harmony Graphics Suite Applications
- What is a driver?
- WDDM Architecture
- Low-Level GPU Documentation
- MiniGLX
- Intel GMA
- Game Architecture and Game Engine
- Z-order curve
- Hilbert curve
- Direct Rendering Manager
- Direct X – Direct way to Microsoft Windows Kernel
- User mode and kernel mode
- Virtual address spaces
- Thread Synchronization and TDR
- Wayland
- Wayland Architecture
- Operating Systems must support GPU abstractions
- Schedule Synthesis for Halide Pipelines on GPUs
- Hardware Accelerated GPU Scheduling
- Windows 10 Hardware-Accelerated GPU Scheduling Benchmarks (Frametimes, FPS)
- TimeGraph: GPU Scheduling for Real-Time Multi-Tasking Environments
- TimeGraph: GPU Scheduling for Real-Time Multi-Tasking Environments
- REAL-TIME SCHEDULING FOR GPUS WITH APPLICATIONS IN ADVANCED AUTOMOTIVE SYSTEMS
- GPU Resource Optimization and Scheduling for Shared Execution Environments
- An Integrated GPU Power and Performance Model
- A user mode CPU–GPU scheduling framework for hybrid workloads
- Balancing Energy Efficiency and Real-Time Performance in GPU Scheduling