상주

GPU가 개체에 액세스할 때 개체가 ‘상주’하는 것으로 간주합니다.

상주 예산

GPU는 페이지 오류를 아직 지원하지 않기 때문에 애플리케이션은 GPU가 데이터에 액세스할 수 있는 동안 데이터를 실제 메모리에 커밋해야 합니다. 이 프로세스는 "무언가를 상주시키는 것"으로 알려져 있으며, 실제 시스템 메모리와 실제 불연속 비디오 메모리 모두에 수행해야 합니다. D3D12에서 대부분의 API 개체는 어느 정도의 GPU 액세스 가능 메모리를 캡슐화합니다. GPU 액세스 가능 메모리는 API 개체 생성 중에 상주하게 되며 API 개체 소멸 시 제거됩니다.

프로세스에 사용 가능한 실제 메모리의 양을 비디오 메모리 예산이라고 합니다. 예산은 백그라운드 프로세스가 절전 모드가 되고 해제될 때마다 크게 변동할 수 있고, 사용자가 다른 애플리케이션으로 전환할 때 크게 변동할 수 있습니다. 예산이 변경되면 애플리케이션에 알림을 보내고 현재 예산과 현재 소비된 메모리 양을 둘 다 폴링할 수 있습니다. 애플리케이션이 예산 내에서 유지되지 않으면 다른 애플리케이션을 실행하거나 생성 API가 실패를 반환할 수 있도록 프로세스가 일시적으로 동결됩니다. IDXGIAdapter3 인터페이스는 이 기능과 관련된 메서드 특히 QueryVideoMemoryInfoRegisterVideoMemoryBudgetChangeNotificationEvent를 제공합니다.

애플리케이션은 예약을 사용하여 반드시 필요한 메모리 양을 나타내는 것이 좋습니다. 이상적으로 사용자가 지정한 "낮음"그래픽 설정 또는 그보다 더 낮은 그래픽 설정이 예약에 적합한 값입니다. 예약을 설정해도 애플리케이션이 일반적으로 수신하는 것보다 높은 예산이 적용되지는 않습니다. 그 보다도, 예약 정보는 OS 커널이 대량 메모리 압력 상황이 미치는 영향을 신속하게 최소화하는 데 도움이 됩니다. 포그라운드 애플리케이션이 아니면, 예약을 해도 애플리케이션에서 사용 가능하다는 보장은 없습니다.

힙 리소스

많은 API 개체가 GPU 액세스 가능 메모리를 캡슐화하지만, 힙 및 리소스는 애플리케이션이 실제 메모리를 소비하고 관리하는 가장 중요한 방식입니다. 힙은 실제 메모리를 관리하는 가장 낮은 수준의 단위이기 때문에 상주 속성에 대해 어느 정도 익숙한 것이 좋습니다.

  • 힙은 부분적으로 상주할 수 없지만 예약된 리소스로 해결하는 방법이 있습니다.
  • 힙은 특정 풀의 일부로 예산을 책정해야 합니다. UMA 어댑터에는 풀이 하나 있지만 불연속 어댑터에는 풀이 두 개 있습니다. 커널이 불연속 어댑터의 일부 힙을 비디오 메모리에서 시스템 메모리로 옮길 수는 있지만 이것은 최후의 수단으로만 사용됩니다. 애플리케이션은 커널의 예산 초과 동작에 의존해서는 안되며 적절한 예산 관리에 중점을 두어야 합니다.
  • 힙은 상주에서 제거될 수 있기 때문에 해당 콘텐츠를 디스크로 페이지 아웃할 수 있습니다. 하지만 힙을 소멸시키는 것이 모든 어댑터 아키텍처에서 상주를 확보하는 데 더 신뢰할 수 있는 기법입니다. D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT MaxGPUVirtualAddressBitsPerProcess 필드가 예산 크기에 가까운 어댑터에서는 제거가 안정적으로 거주를 회수하지 않습니다.
  • 힙 생성은 느릴 수 있지만 백그라운드 스레드 처리를 위해 최적화되어 있습니다. 렌더링 스레드에 결함이 발생하지 않도록 백그라운드 스레드에서 힙을 생성하는 것이 좋습니다. D3D12에서는, 여러 스레드가 동시에 생성 루틴을 안전하게 호출할 수 있습니다.

D3D12는 애플리케이션에 더 많은 옵션을 사용할 수 있도록 리소스 모델에 더 많은 유연성과 직교성을 제공합니다. D3D12에는 커밋, 배치 및 예약이라는 3가지 상위 수준의 리소스 유형이 있습니다.

  • 커밋된 리소스는 리소스와 힙을 동시에 만듭니다. 힙은 암시적이기 때문에 직접 액세스할 수 없습니다. 힙은 힙 내의 전체 리소스를 찾을 수 있도록 적절하게 크기가 조정됩니다.
  • 배치된 리소스를 사용하면 힙 내 0이 아닌 오프셋에 리소스를 배치할 수 있습니다. 오프셋은 대개 64KB로 맞춰야 하지만 양방향에 몇 가지 예외가 있습니다. MSAA 리소스에는 4MB 오프셋 맞춤이 필요하며 작은 질감에는 4KB 오프셋 맞춤이 가능합니다. 배치된 리소스는 또 다른 힙으로 직접 재배치하거나 다시 매핑할 수 없지만, 힙 간에 리소스 데이터를 간단히 재배치할 수 있습니다. 다른 힙에 배치된 새 리소스를 만들고 리소스 데이터를 복사한 후에는 새 리소스 데이터 위치에 새 리소스 설명자를 사용해야 합니다.
  • 예약된 리소스는 어댑터가 타일식 리소스 계층 1 이상을 지원하는 경우에만 사용할 수 있습니다. 가능한 경우 최상의 상주 관리 기법을 제공하지만, 현재 일부 어댑터는 이것을 지원하지 않습니다. 리소스 설명자, 부분 밉 수준 상주 및 스파스 텍스처 시나리오 등을 다시 생성할 필요 없이 리소스를 다시 매핑할 수 있습니다. 예약된 리소스를 사용할 수 있는 경우에도 모든 리소스 유형이 지원되지 않으므로 완전히 일반적인 페이지 기반 상주 관리자는 아직 불가능합니다.

상주 우선 순위

Windows 10 크리에이터스 업데이트를 사용하면 메모리 압력으로 인해 일부 리소스를 강등해야 하는 경우 우선적으로 상주할 힙과 리소스에 개발자가 영향을 미칠 수 있습니다. 이를 통해 개발자는 런타임에서 API 사용을 통해 추측할 수 없다는 지식을 활용하여 보다 우수한 성능의 애플리케이션을 만들 수 있습니다. 개발자가 커밋된 리소스에서 예약된 리소스 및 타일식 리소스로 사용을 전환하기 하기 때문에 편리성이 향상되고 우선 순위를 지정할 수 있을 것으로 예상됩니다.

이러한 우선 순위를 적용하는 것은 두 가지 동적 메모리 예산을 관리(둘 사이에서 리소스를 수동으로 강등 및 승격)하는 것보다 보다 쉽습니다. 애플리케이션이 해당 작업을 이미 수행할 수 있기 때문입니다. 따라서 상주 우선 순위 API 설계는 각 힙 또는 리소스가 생성될 때 할당된 합당한 기본 우선 순위로 대략적으로 세분화됩니다. 자세한 내용은 ID3D12Device1::SetResidencyPriorityD3D12_RESIDENCY_PRIORITY 열거형을 참조하세요.

우선 순위에 따라 개발자는 다음 중 하나를 수행해야 합니다.

  • 자연스러운 액세스 패턴이 요구하는 것보다 더 빨리 또는 더 자주 강등되는 힙의 성능에 미치는 영향을 효과적으로 완화하도록 몇 가지 예외적인 힙 우선 순위를 높입니다. 이러한 방식은 리소스 관리 모델이 Direct3D 12와 상당히 다른 Direct3D 11이나 OpenGL과 같은 그래픽 API에서 포팅된 애플리케이션에서 활용될 것으로 예상됩니다.
  • 거의 모든 힙 우선 순위를 액세스 빈도에 대한 프로그래머의 지식에 기반하여 애플리케이션 자체 버킷화 스키마(고정 또는 동적)로 덮어씁니다. 고정 스키마는 동적 스키마보다 관리가 더 간단하지만, 개발 과정에서 사용 패턴이 변하면 효율성이 떨어지며 프로그래머의 개입이 필요합니다. 이 방식은 상주 라이브러리(특히 동적 스키마)를 사용하는 Direct3D 12 스타일 리소스 관리를 감안하여 구축된 애플리케이션에서 활용될 것으로 예상됩니다.

기본 우선 순위 알고리즘

기본 우선 순위 알고리즘을 먼저 이해하지 않고는 애플리케이션이 관리하려는 힙에 대해 유용한 우선 순위를 지정할 수 없습니다 그 이유는 특정 우선 순위를 힙에 할당하는 값이 동일한 메모리에 대해 경쟁하는 다른 우선 순위의 힙에 대한 상대적 우선 순위에서 파생되기 때문입니다.

기본 우선 순위를 생성하기 위해 선택한 전략은 GPU에서 자주 쓰는 것으로 가정되는 힙을 그렇지 않은 힙보다 선호(높은 우선 순위를 부여)하는 두 개의 버킷으로 분류하는 것입니다.

우선 순위가 높은 버킷에는 렌더링 대상, 깊이 스텐실 버퍼 또는 UAV(순서가 지정되지 않은 액세스 뷰)로 식별되는 플래그로 생성되는 힙 및 리소스가 포함됩니다. 이러한 힙과 리소스 중에서 우선 순위를 더 지정하기 위해 D3D12_RESIDENCY_PRIORITY_HIGH 범위의 우선 순위 값이 할당되며, 우선 순위의 가장 낮은 16비트가 10MB로 분할된 힙 또는 리소스의 크기로 설정됩니다(매우 큰 힙의 경우 0xFFFF 포화). 이 추가 우선 순위에는 더 큰 힙과 리소스가 선호됩니다.

우선 순위가 낮은 버킷에는 D3D12_RESIDENCY_PRIORITY_NORMAL 우선 순위 값이 할당된 다른 모든 힙 및 리소스가 포함됩니다. 힙과 리소스에 대한 더 이상의 우선 순위 지정은 시도되지 않습니다.

상주 관리 프로그래밍

간단한 애플리케이션은 메모리 부족 오류가 발생할 때까지 커밋된 리소스를 생성하는 것으로 어떻게든 처리해나갈 수 있습니다. 실패 시, 애플리케이션은 더 많은 리소스 생성이 성공하도록 커밋된 다른 리소스나 API 개체를 삭제할 수 있습니다. 하지만 간단한 애플리케이션이라도 부정적인 예산 변경을 지켜보고 프레임 하나에 대략 한 번 사용하지 않는 API 개체는 삭제하는 것이 좋습니다.

어댑터 아키텍처를 최적화하거나 상주 우선 순위를 통합하려고 하면 상주 관리 설계의 복잡성이 높아집니다. 두 개의 불연속 메모리 풀을 별도로 예산 및 관리하는 것은 하나만 관리하는 것보다 더 복잡하며, 사용 패턴이 진화할 경우 고정 우선 순위를 대규모로 할당하면 기본 달성 부담이 될 수 있습니다. 시스템 메모리로 질감이 오버플로되면 시스템 메모리의 잘못된 리소스가 프레임 속도에 심각한 영향을 줄 수 있기 때문에 복잡성이 커집니다. 높은 GPU 대역폭의 혜택을 누리거나 낮은 GPU 대역폭을 허용하는 리소스를 식별하는 데 도움이 되는 간단한 기능은 없습니다.

훨씬 더 복잡한 디자인은 현재 어댑터의 기능을 쿼리합니다. 이 정보는 D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT, D3D12_FEATURE_DATA_ARCHITECTURE, D3D12_TILED_RESOURCES_TIERD3D12_RESOURCE_HEAP_TIER 사용할 수 있습니다.

애플리케이션의 여러 부분은 다양한 기법을 사용하여 작동할 수 있습니다. 예를 들어, 큰 질감 및 거의 수행되지 않는 코드 경로에는 커밋된 리소스를 사용할 수 있지만, 많은 질감은 스트리밍 속성으로 지정되어 일반적인 배치 리소스 기법을 사용할 수 있습니다.

ID3D12Heap

메모리 관리