다음을 통해 공유


DirectStorage 개요

소개

이 문서에서는 Xbox Series X|S 콘솔에 대해서만 DirectStorage API에 대한 개요를 제공합니다. 데스크톱의 DirectStorage에 대한 세부 정보는 데스크톱의 DirectStorage를 참조하세요.

PCIe 버스를 사용하여 연결된 최신 NVMe 저장 장치는 매우 높은 수준의 처리량 및 IOPS(초당 I/O 요청)을 달성할 수 있습니다. Win32 API의 오버헤드는 사용 가능한 저장소 대역폭을 활용할 수 있지만 이를 활용할 때 CPU 사용률이 과도하게 증가할 수 있음을 의미합니다. 워크로드가 많은 수의 작은 요청으로 구성된 경우 특히 그렇습니다.

DirectStorage API는 기본 NVMe 하드웨어와 긴밀하게 상호 작용하여 대부분의 운영 체제 오버헤드를 제거하도록 설계되었습니다. 이를 통해 낮은 CPU 사용량으로 더 높은 대역폭을 달성할 수 있습니다. 목표는 단일 CPU 코어의 최대 10%를 사용하면서 초당 최대 50,000개의 요청을 처리할 수 있도록 하는 것입니다.

기존 문제

각 콘솔 생성에 따라 더 높은 해상도 자산에 대한 필요성이 증가함에 따라 게임 콘텐츠가 점점 더 커지고 있습니다. 기존 Xbox One 하드웨어 및 소프트웨어에는 개발자가 이 차세대 콘텐츠를 위해 하드 드라이브에서 메모리로 데이터를 가져오는 기능을 방해하는 몇 가지 제한 사항이 있습니다.

  • 높은 CPU 사용량

    • 기존 Win32 API가 오버헤드에서 전체 CPU 코어를 요구할 수 있습니다.
    • 이는 타이틀의 요청 수와 크기를 기반으로 합니다.
  • 디스크의 최대 대역폭이 부족합니다.

  • 디스크 요청의 우선 순위를 정할 수 없음

    • 타이틀 요청의 우선 순위를 지정할 수 없으면 반응형 스트리밍 시스템을 만들기 어려울 수 있습니다.
  • 디스크 요청을 취소할 수 없음

    • 요청을 취소하는 기능이 없으면 추론적 읽기 시스템을 생성하기 어려울 수 있습니다.
  • 하드웨어 가속 압축 풀기 안 함

    • 하드웨어 가속 압축 풀기를 사용하지 않으면 소프트웨어에서 압축 풀기를 수행하는 데 많은 CPU 리소스가 필요할 수 있습니다.

DirectStorage API 집합은 이러한 각 문제를 직접 해결합니다. 전반적인 효과는 Xbox 파일 시스템의 성능을 크게 향상시킵니다.

CPU 사용량

DirectStorage의 기본 디자인 목표는 타이틀이 50K IOPS를 유지하고 단일 CPU 코어의 5%에서 10% 사이만 사용할 수 있도록 하는 것입니다. 이를 통해 타이틀은 NVMe 저장소 하위 시스템에서 최대 대역폭을 달성하는 동시에 다른 타이틀 요구 사항에 CPU를 사용할 수 있습니다.

DirectStorage는 하드웨어 압축 풀기도 지원합니다. 각 읽기 요청은 NVMe 드라이브에서 내장 하드웨어 압축 해제 블록으로 직접 라우팅될 수 있습니다. 따라서 타이틀에서 압축 해제에 CPU 리소스를 사용할 필요가 없습니다.

대기 중인 파이프라인 모델

DirectStorage는 여러 요청이 큐에 추가되는 일괄 처리 방법을 사용합니다. 나중에 큐가 다음 파이프라인 단계로 플러시됩니다. 이렇게 하면 파이프라인 단계 간 전환에 대한 전반적인 CPU 비용이 즉시 줄어듭니다. 기존 Win32 API 집합에는 각 요청에 대한 전환이 있습니다. DirectStorage 큐는 잠금을 사용하지 않는 알고리즘을 사용하여 경합을 최소화합니다. 각 큐가 플러시될 때 해당 타이틀의 제어 권한이 부여됩니다.

Win32 API가 있는 대부분의 경우 디스크의 데이터를 다른 버퍼에 복사해야 할 수 있습니다. 경우에 따라 데이터를 두 번 이상 복사해야 할 수 있습니다. DirectStorage는 타이틀 제공 대상 버퍼를 각 파이프라인 계층에 직접 매핑하여 이 문제를 해결합니다. 하드웨어는 타이틀에서 제공하는 버퍼에 직접 기록됩니다.

이러한 변경으로 CPU 오버헤드가 크게 줄어듭니다.

압축 해제

하드웨어가 데이터를 압축 해제하는 기능이 향상되었습니다. 이제 NVMe 하위 시스템이 데이터를 제공할 수 있는 속도보다 더 빠르게 다양한 형식을 처리할 수 있습니다. 또한 DirectStorage는 적절한 압축 해제를 지원하므로 압축 및 압축 해제된 데이터에 대해 별도의 버퍼를 관리할 필요가 없습니다.

하드웨어는 , 를 DEFLATE지원BCPACK하며 최종 콘텐츠를 스위즐하는 기능을 제공합니다. 이러한 형식은 상호 배타적인 것이 아닙니다. 세 가지 모두 데이터에 적용할 수 있습니다. 이렇게 하면 타이틀에 최상의 압축 비율과 성능을 제공하는 방법을 선택할 수 있습니다. 자산마다 서로 다른 압축 및 스위즐 설정을 사용할 수 있습니다.

큐 깊이

이전 권장 사항은 회전 드라이브에서 한 번에 12~16개의 비동기 요청만 유지하는 것이었습니다. 더 큰 것은 성능에 아무런 이점이 없었고, 더 작게 하면 성능이 크게 저하될 수 있습니다. 이로 인해 타이틀이 미해결 읽기 요청의 균형을 맞춰 권장 대상 내에 유지하기 위해 추가 작업을 수행하게 되었습니다.

타이틀이 50,000 IOPS를 달성할 수 있도록 하는 DirectStorage 목표를 통해 권장 사항이 변경되었습니다. 타이틀은 더 이상 미해결 작업과 큐 깊이 사이에서 균형을 유지하려고 할 필요가 없습니다. 타이틀은 모든 미해결 요청을 제출해야 합니다. 일부 요청을 보류하는 것에 대한 이점은 없습니다. 대부분의 경우 요청을 다시 보류하면 하드웨어가 중단되어 새 요청을 기다리는 동안 성능이 저하될 수 있습니다.

운영 체제는 더 큰 읽기 요청을 몇 가지 작은 요청(예: 디스크 조각화 처리)으로 분할하는 데 여전히 필요합니다. 하지만 이 사항은 DirectStorage 아키텍처에서 고려되었습니다. 50,000 IOPS 설계 목표는 하드웨어에 대한 최종 요청이 아니라 IO 작업의 타이틀 수를 기반으로 합니다.

알림

Win32 아키텍처에서는 읽기 완료 알림에 많은 양의 오버헤드가 소비됩니다. 타이틀은 OVERLAPPED 구조를 폴링하거나, 연결된 이벤트 핸들을 기다리거나, 동기 차단 읽기를 수행할 수 있습니다. 전반적으로 이로 인해 각 읽기 요청의 리소스 요구가 증가합니다.

DirectStorage는 알림의 두 비동기 개념을 유지하면서 세 번째 메서드를 추가합니다. DirectStorage에서는 동기 차단 읽기가 지원되지 않으므로 타이틀이 자체 시스템을 구현할 수 있습니다. 그러나 권장되지는 않습니다.

첫 번째 비동기 메서드는 연관된 요청이 완료될 때 설정되는 상태 차단을 통해 구현됩니다. 타이틀은 읽기 완료 시점을 결정하기 위해 필요에 따라 차단을 폴링할 수 있습니다. 이는 완료를 위해 OVERLAPPED 구조를 폴링하는 Win32 메서드와 비슷합니다.

두 번째 비동기 메서드는 Windows Event 개체를 사용하여 완료 신호를 보냅니다. 이는 해당 Event 개체와 함께 OVERLAPPED 구조를 사용하는 것과 유사합니다. 타이틀은 WaitForSingleObject 메서드를 사용하여 읽기 작업이 완료될 때까지 호출 스레드가 일시 중단되도록 할 수 있습니다.

세 번째 비동기 메서드는 ID3D12Fence를 사용하여 구현됩니다. 타이틀은 펜스 대기를 일시 중단하거나 필요한 경우 울타리를 폴링할 수 있습니다. 완료된 요청을 직접 알리기 위해 GPU가 펜스를 사용할 수 있다는 이점도 있습니다.

DirectStorage 알림 시스템은 단일 읽기 요청에 바인딩되지 않습니다. 이전의 모든 읽기 요청이 완료되면 신호를 받는 큐에 배치된 항목입니다. 이렇게 하면 타이틀이 알림에 필요한 세분성을 제어할 수 있습니다. 알림은 항상 큐 순서로 신호를 받습니다. 큐는 FIFO(선입 선출) 큐로 간주될 수 있습니다. 타이틀은 마지막 관련 알림만 쿼리하면 됩니다. 이전에 큐에 추가된 모든 요청은 완료됩니다.

메모리 간 압축 해제

DirectStorage는 디스크 파일 대신 메모리를 압축 해제 원본으로 하여 압축 해제 하드웨어를 호출할 수 있는 큐 형식을 제공합니다. 이렇게 하면 압축된 자산이 파일에서 원본화되지 않았거나 이전에 원본이 되어 캐시로 메모리에 보관된 경우 압축 해제 하드웨어를 활용할 수 있습니다. 메모리 원본 큐에는 메모리 원본 요청만 허용되고, 파일 원본 큐에는 파일 원본 요청만 허용됩니다.

메모리 원본 요청에 압축 해제 옵션이 지정되지 않은 경우 압축 해제 하드웨어가 DMA 복사 엔진으로 작동할 수도 있습니다.

DirectStorage는 완료 알림을 순서대로 보장하지만 요청 처리를 시작할 시점은 보장하지 않습니다. 따라서 보류 중인 요청 간에 데이터 종속성이 없어야 합니다. 즉, 요청 A가 완료된 후 요청 B가 큐에 추가되지 않는 한 요청 A의 대상을 요청 B의 원본으로 사용할 수 없습니다.

메모리 기반 큐는 실시간 우선 순위를 사용하여 만들어야 합니다. 또한 메모리 기반 실시간 요청은 압축 해제가 필요한 디스크 기반 요청을 하기 전에 먼저 처리하는 것이 좋습니다. 디스크 원본 큐에 압축 해제 요청이 없는 경우 두 큐 형식은 다른 형식에 영향을 주지 않고 완전히 병렬로 처리됩니다.

우선 순위

DirectStorage를 통해 각 큐에 우선 순위 수준이 할당됩니다. 큐의 각 항목은 큐의 우선 순위를 상속합니다. 실시간, 높음, 보통, 낮음의 네 가지 우선 순위 수준이 제공됩니다. 요청은 가중 라운드 로빈 방식으로 처리됩니다. 예를 들어 우선 순위가 보통인 하나의 요청을 처리하기 전에 우선 순위가 높은 X 요청을 처리합니다. 우선 순위가 낮은 하나의 요청을 처리하기 전에 우선 순위가 보통인 Y 요청을 처리합니다.

우선 순위 가중치는 각 요청의 크기에 따라 계산됩니다. 각 우선 순위 간의 기본 가중치는 약 10배입니다. 즉, 우선 순위가 낮은 요청 1KB, 중간 우선 순위 요청 10KB, 우선 순위가 높은 요청 100KB가 처리되었습니다.

기존 Win32 읽기 요청은 동일한 우선 순위 시스템을 통해 라우팅됩니다. 모든 Win32 요청은 보통 우선 순위로 간주됩니다.

메모리 기반 큐는 실시간 우선 순위를 사용하여 만들어야 합니다.

취소

각 DirectStorage 읽기 요청에는 타이틀 제공 64비트 마스크가 연결되어 있습니다. 보류 중인 읽기 요청의 취소를 지원하기 위한 것입니다. 타이틀은 마스크 내의 특정 플래그 집합과 일치하는 요청을 취소할 수 있습니다.

취소가 지원되더라도 하드웨어가 읽기 요청을 처리할 수 있습니다. 타이틀 취소 요청은 최상의 시도입니다. 요청이 하드웨어에서 이미 처리 중인 경우 취소할 수 없습니다.

취소 요청은 최선의 시도이므로 타이틀은 읽기 요청 처리가 완료될 때까지 기다려야 합니다. 큐에서 나중에 알림을 받을 때까지 타이틀은 필요한 리소스를 릴리스할 수 없습니다. 그러나 이 기간 동안 이전 취소 요청에 사용된 플래그와 일치하는 새 요청을 큐에 추가할 수 있으며 취소되지 않습니다.

취소된 요청이 완료되면 취소되고 전체 결과를 생성하지 않은 경우에도 성공한 것으로 간주됩니다. 즉, 요청에서 취소를 시도하는 경우 타이틀은 완료 시 잠재적으로 취소된 요청의 결과를 더 이상 사용할 수 없습니다.

보장

Xbox One 및 Xbox One S 본체에는 최소 40MB/s가 보장됩니다. Xbox One X 본체는 최소 보장을 60MB/s로 늘렸습니다. 이러한 수치는 130MB/s 범위에 있는 실제 하드웨어 제한보다 훨씬 낮습니다. 이는 운영 체제로 인한 오버헤드 때문입니다.

DirectStorage는 운영 체제에서 발생하는 대부분의 오버헤드를 제거합니다. 이렇게 하면 하드웨어 제한에 가까운 최소 보장이 허용됩니다. 새로운 최소 성능 보장은 원시 데이터에 대해 250ms 범위에서 2.0GB/s입니다. 콘텐츠에 대한 압축 해제를 사용하면 최종 대역폭이 더 높아집니다.

향후 Xbox 본체는 NVMe 기반의 동적 사용자 설치 가능 드라이브 추가를 지원합니다. 내장형 드라이브에 대해 제공되는 것과 동일한 최소 성능 보장도 사용자 설치 가능 드라이브에 제공됩니다.

API 개요

DirectStorage 인터페이스는 Direct3D 인터페이스와 동일한 패턴을 따릅니다. 처음에는 타이틀이 싱글톤 팩터리를 획득합니다. 팩토리는 요청 큐를 만들고 파일을 여는 데 사용됩니다. 이러한 개체는 각각 하드웨어에 직접 매핑됩니다. 그런 다음 개별 요청이 큐에 추가되어 하드웨어에 제출됩니다.

IDStorageFactoryX

IDStorageFactoryX는 큐를 만들고, 파일을 열고, 보류 중인 요청을 제출하기 위한 기본 인터페이스입니다.

개체에는 IDStorageFactoryX 다음 메서드가 있습니다.

  • OpenFile

    • IDStorageFileX 하나의 파일을 나타내는 개체를 만듭니다.
  • CreateQueue

    • 개체를 IDStorageQueueX 만듭니다. 읽기 요청을 만드는 데 사용됩니다.
  • CreateStatusArray

    • 완료 상태 IDStorageStatusArray 플래그를 관리하는 개체를 만듭니다.
  • SetCPUAffinity

    • DirectStorage의 out-of-calling-thread 작업을 타이틀 정의 CPU 코어 집합으로 제한합니다.
    • 참고 DirectStorage는 호출 스레드에서 대부분의 작업을 수행하고자 시도합니다. out-of-calling-thread 작업은 호출 스레드에서 작업을 수행할 수 없는 경우에만 발생합니다. 예시는 다음과 같습니다.
      • 동안 기본 리소스 파이프라인이 가득 차 IDStorageQueueX::Submit서 큐의 모든 요청을 푸시할 수 있는 것은 아닙니다. 나머지 요청은 나중에 리소스가 확보되면 처리되고 DirectStorage 작업자 스레드에서 수행됩니다.
      • 또는 IDStorageStatusArrayID3DFence 대한 요청 완료 처리
  • SetDebugFlags

    • DirectStorage가 디버깅을 지원하기 위해 요청 큐에서 추가 유효성 검사를 수행할지 여부를 제어합니다.
  • SetStagingBufferSize

    • 스토리지 디바이스에서 로드된 콘텐츠를 암호 해독/압축 해제하기 전에 일시적으로 저장하는 데 사용되는 스테이징 버퍼의 크기를 설정합니다. 메모리 소스인 큐만 사용돠는 경우에는 스테이징 버퍼의 크기가 0이 될 수 있습니다.

IDStorageFactoryX1

인터페이스는 IDStorageFactoryX1GetStatsIDStorageFactoryX 메서드를 통해 인터페이스를 확장합니다.

  • GetStats
    • DirectStorage 통계를 가져옵니다. 이 기능은 DirectStorage를 기존 진단 및 원격 분석 파이프라인과 통합하는 데 사용할 수 있습니다. 처리가 최소화되어 자주 호출될 수 있습니다. 통계에는 Win32 파일 IO 작업이 포함되지 않습니다.

IDStorageFileX

모든 파일은 개체를 통해 IDStorageFactoryX DirectStorage에서 처음에 열어야 합니다. 이는 Win32 API 인터페이스에서 CreateFile을 사용하는 것과 같습니다.

권한이 있는 파일이 열립니다 FILE_SHARED_READ . 필요한 경우 타이틀은 적절한 권한이 적용되는 경우 Win32 API를 사용하여 파일을 동시에 열 수 있습니다. 개발 중 느슨한 배포 및 패키지 배포가 모두 지원됩니다.

파일 개체에서 Close 함수를 명시적으로 호출하거나 일치하는 IDStorageFileX 개체에 대한 마지막 참조가 해제되면 파일이 닫힙니다. 그러나 보류 중인 모든 I/O 작업을 완료해야 파일을 닫을 수 있습니다. 즉, 해당 파일에 대한 모든 미해결 I/O 작업이 완료될 때까지 파일을 닫기 위한 두 가지 방법 모두 차단이 됩니다.

게임은 GetHandle 함수를 호출하여 개체가 IDStorageFileX 나타내는 파일에 대한 win32 핸들을 가져올 수 있습니다. 핸들은 GENERIC_READ 사용 권한과 FILE_SHARE_READ 공유 모드를 통해 열립니다. 파일의 크기 등을 쿼리하는 데 사용할 수 있습니다. 핸들은 더 이상 필요하지 않을 때 를 사용하여 CloseHandle() 닫아야 합니다.

IDStorageQueueX

읽기 요청은 개체를 통해 NVMe에 IDStorageQueueX 제출됩니다. 그러나 큐에서 타이틀이 Submit을 호출하거나 마지막 제출 이후 큐 용량의 절반 이상을 채운 Enqueue 메서드 중 하나가 자동 제출을 트리거할 때까지 요청이 장치에 제출되지 않습니다. 제출은 파이프라인에서 다음 단계에 대한 단일 전환으로 처리됩니다. 이를 통해 타이틀과 커널 간 전환에 CPU 비용이 발생하는 시기를 제어할 수 있습니다.

IDStorageQueueX 개체에는 네 가지 속성이 있습니다.

  • SourceType

    • 큐가 파일 원본 요청 또는 메모리 원본 요청을 받을 수 있는지 여부를 지정합니다.
  • 우선 순위

    • 큐에 제출된 모든 요청의 우선 순위: 실시간, 높음, 보통 또는 낮음.
    • 메모리 기반 큐는 실시간 우선 순위를 사용하여 만들어야 합니다.
    • 요청은 우선 순위에 따라 가중 라운드 로빈 순서로 처리됩니다.
    • Win32 요청은 보통 우선 순위 수준에서 처리됩니다.
  • Capacity

    • 큐가 보유할 수 있는 최대 미해결 요청 수입니다.
    • 큐가 작동 중일 때 요청을 큐에 넣으려고 하면 하드웨어가 항목을 완료할 때까지 차단됩니다.
    • 큐에 필요한 메모리 양은 대략 큐 용량에 의 크기를 곱합니다 DSTORAGE_REQUEST.
  • 이름

    • 전적으로 디버깅에 유용합니다. 이름은 DirectStorage 코드에서 사용되지 않지만 PIX(NDA 항목)권한 부여 필요와 같은 개발자 도구에는 표시될 수 있습니다.

하드웨어는 처리량을 극대화하기 위해 비동기적으로 요청을 처리합니다. 하지만 Win32와 달리 타이틀은 FIFO 순서로 완료될 때 알림을 받습니다. 완료 알림을 받으면 동일한 큐에 대한 모든 이전 요청도 완료되었음이 보장됩니다.

IDStorageQueueX1

인터페이스는 IDStorageQueueX1EnqueueSetEvent 메서드를 사용하여 인터페이스를 확장 IDStorageQueueX 합니다.

EnqueueRequest

이 인터페이스는 Win32 ReadFile 인터페이스와 기능적으로 동일합니다. 개별 읽기 요청이 생성되어 큐에 제출됩니다. 가장 큰 차이점은 DirectStorage에서는 많은 요청이 제출 전에 큐에서 대기할 수 있고 하드웨어 압축 해제 및 취소를 지원한다는 것입니다.

요청에는 다음과 같은 몇 가지 기본 속성이 있습니다.

요청의 원본
Options.SourceIsPhysicalPagesOptions.SourceType 조합에 따라 DirectStorage는 다음 세 가지 속성 그룹 중 하나를 사용하여 원본 데이터가 있는 위치를 지정합니다.

  • FileFileOffset

    • 이 그룹은 가 인 경우에 Options.SourceType 사용됩니다. DSTORAGE_REQUEST_SOURCE_FILE
    • 파일 은 이전에 를 사용하여 열렸습니다 IDStorageFactoryX::OpenFile.
    • 압축 해제를 사용하는 경우 FileOffset을 16 바이트 정렬해야 하거나 압축 해제를 사용하지 않는 경우 정렬 요구 사항이 없습니다.
      • 비동기 읽기를 위해 파일 내에서 4KiB 정렬이 필요한 Win32의 주요 변경 사항입니다.
  • Source

    • 이 그룹은 가 DSTORAGE_REQUEST_SOURCE_MEMORY 이고 FALSEOptions.SourceIsPhysicalPages 가 인 경우에 Options.SourceType 사용됩니다.
    • 압축을 해제할 데이터를 보유하고 있는 메모리 버퍼입니다.
  • SourcePageArraySourcePageOffset

    • 이 그룹은 가 DSTORAGE_REQUEST_SOURCE_MEMORY 이고 TRUEOptions.SourceIsPhysicalPages 가 인 경우에 Options.SourceType 사용됩니다.
    • Source와 비슷하지만 64KB 실제 페이지 배열의 형태로 원본 메모리 버퍼를 제공하고 첫 번째 페이지의 바이트 오프셋을 제공합니다.
    • 물리적 64KB 페이지는 에서 XMemAllocatePhysicalPages할당할 수 있습니다.

SourceSize

  • 메모리 버퍼 또는 파일에서 읽을 원본 데이터의 크기(바이트)입니다.

IntermediateSize

  • 이 요청 IntermediateSize 에서 및 BCPACK압축 해제를 모두 zlib 사용하는 경우 은 원본 데이터 zlib-decompresses(및 BCPACK-decompresses from)에 대한 중간 크기를 지정하는 데 사용됩니다.
  • 그렇지 않은 경우에는 0으로 설정해야 합니다.

요청의 대상
Options.DestinationIsPhysicalPages따라 DirectStorage는 다음 두 속성 그룹 중 하나를 사용하여 대상이 있는 위치를 지정합니다.

  • Destination

    • 이 그룹은 가 인 경우에 Options.DestinationIsPhysicalPagesFALSE사용됩니다.
    • 최종 로드된 데이터를 위한 대상 버퍼입니다.
    • 압축 해제는 공유 내부 버퍼를 사용하여 발생하며 실행 중인 것으로 간주될 수 있습니다.
  • DestinationPageArrayDestinationPageOffset

    • 이 그룹은 가 인 경우에 Options.DestinationIsPhysicalPagesTRUE사용됩니다.
    • Destination 와 비슷하지만 첫 번째 페이지의 64KB 실제 페이지 배열과 바이트 오프셋의 형태로 대상 메모리 버퍼를 제공합니다.
    • 물리적 64KB 페이지는 에서 XMemAllocatePhysicalPages할당할 수 있습니다.

DestinationSize

  • 로드된 최종 콘텐츠의 예상 크기(바이트)입니다. 대상에 작업을 수용할 충분한 공간이 있어야 합니다.
  • 아 크기는 압축 해제를 사용하지 않는 경우 SourceSize와 동일하거나 압축 해제를 사용하는 경우 SourceSize보다 커야 합니다.

CancellationTag

  • 타이틀로 정의된 임의의 64비트 태그입니다.
  • 이 태그는 취소 요청에 대한 마스크로 사용됩니다.

이름

  • 디버깅에 도움이 되는 선택적 문자열입니다. 이름은 PIX(NDA 항목)권한 부여 필요와 같은 개발자 도구 또는 에서 IDStorageQueueX::RetrieveErrorRecord가져온 오류 레코드에 나타날 수 있습니다. 요청의 Name 수명을 통해 문자열에 액세스할 수 있어야 합니다.

옵션

  • ZlibDecompress
    • RFC 1950 압축 해제 표준을 사용하여 데이터를 압축 해제해야 한다는 점을 나타냅니다.
  • BcpackMode
    • 데이터를 압축 해제하는 데 사용해야 하는 모드 BCPACK 를 나타냅니다.
    • 없음은 유효한 옵션이며 데이터가 압축되지 않음 BCPACK 을 의미합니다.
  • SwizzleMode
    • 최종 데이터를 메모리에 스위즐 처리하는 방법을 나타냅니다. 현재 릴리스에 있어야 DSTORAGE_SWIZZLE_MODE_NONE 합니다.
  • DestinationIsPhysicalPages
    • 대상 버퍼가 Destination 대신 DestinationPageArrayDestinationPageOffset을 사용하여 지정되었음을 나타냅니다.
  • SourceType
    • 요청은 메모리 원본이 될 수 있으므로 Source/ SourcePageArraySourcePageOffset 속성 또는 파일 소스가 있으므로 속성이 File/FileOffset 있습니다.
  • SourceIsPhysicalPages
    • 원본 버퍼가 Source 대신 SourcePageArraySourcePageOffset을 사용하여 지정되었음을 나타냅니다.

EnqueueStatus/EnqueueSignal/EnqueueSetEvent

요청은 일련의 관련 요청으로 큐에 추가하고 처리될 수 있습니다. 처리 상태가 큐의 특정 지점에 도달했을 때 알림을 위해 큐에 추가하는 방식으로 수행됩니다. 알림은 이전의 모든 읽기 요청이 완료된 경우에만 처리됩니다. 이렇게 하면 이전의 모든 요청에서 데이터를 즉시 사용할 수 있습니다.

타이틀에는 두 개의 폴링 방법과 알림 대기 방법이 있습니다. 제목은 개체 또는 개체 또는 IDStorageStatusArrayX 이벤트 설정 작업을 삽입 ID3D12Fence 할 수 있습니다. 는 ID3D12Fence 개체에 대해 ID3D12Fence 예상대로 동작합니다. 타이틀 스레드는 에서 Event대기할 수 있으며 CPU는 펜스를 폴링할 수 있으며 GPU는 펜스를 폴링할 수 있습니다. 개체를 IDStorageStatusArrayX 사용하면 CPU에서 완료를 위해 폴링하고 가능한 읽기 실패에 액세스할 수 있습니다. 메서드 EnqueueSetEvent 를 사용하면 타이틀 스레드가 폴링 대신 지정된 이벤트를 기다릴 수 있습니다. ID3D12Fence::SetEventOnCompletion 이는 Xbox 구현 ID3D12Fence::SetEventOnCompletion 이 신호가 전송될 때까지 펜스에서 회전하므로 신호까지 CPU 하드웨어 스레드를 사용하는 반면 EnqueueSetEvent 타이틀 스레드는 이벤트를 신호할 때까지 CPU를 다른 스레드에 생성하는 데 사용할 WaitForSingleObject/WaitForMultipleObjects 수 있습니다.

앞서 언급했듯이 기본 하드웨어가 성능을 위해 순서를 변경하기로 결정한 경우에도 모든 요청이 순서대로 완료됩니다. 알림은 큐에 있는 이전의 모든 요청이 완료될 때까지 신호를 받을 수 없습니다.

압축 해제

압축 해제는 전용 하드웨어를 사용하여 처리됩니다. 이렇게 하면 기존 압축 해제 알고리즘에서 CPU 오버 헤드가 제거됩니다. DirectStorage는 압축 해제를 위해 작업 버퍼로 사용하도록 초기화되는 동안 고정된 메모리 블록을 할당합니다. 이를 통해 적절한 압축 해제가 가능하며 압축된 데이터와 압축 해제된 데이터를 동시에 메모리에 보관할 필요가 없습니다.

압축 해제 하드웨어는 세 가지 작동 모드를 지원합니다. 이들 모드는 상호 배타적이지 않으므로 모드 조합을 지정할 수 있습니다. 압축 해제 모드는 , BCPACKSwizzle순서DEFLATE로 적용됩니다.

  • ZLibDecompress

  • BCPack

    • BCPack 는 BCn 데이터를 위해 특별히 설계된 사용자 지정 엔트로피 코더입니다. 일반적으로 색 끝점이 팔레트 인덱스(즉, 가중치)와 분리되고 rANS 알고리즘을 사용하여 압축된다는 의미입니다.
  • Swizzle

    • Swizzle 및 순서 섞기 모드는 콘텐츠 파이프라인에서 추가 최적화를 제공할 수 있습니다.

높은 엔트로피 데이터가 압축되면 압축이 실제로 크기가 증가할 수 있습니다. 반대로 해당 압축 해제는 크기가 축소됩니다. DirectStorage는 압축 해제를 축소할 수 없으며, 압축할 수 없는 높은 엔트로피 데이터를 검색하고 이러한 자산에 대한 압축을 피하는 것은 타이틀의 책임입니다. 자세한 내용은 DirectStorage 및 XTBC(NDA 항목)를 사용하여 압축된 콘텐츠를 최적화하는 방법권한 부여 필요에 관한 가이드를 참조하세요.

스테이징 버퍼

DirectStorage는 내부적으로 버퍼를 사용하여 암호 해독 및 압축 해제와 같은 작업을 수행하기 전에 원시 NVMe 스토리지에서 읽은 모든 콘텐츠를 스테이징합니다. 이 스테이징 버퍼를 사용하면 NVMe 드라이브와 암호 해독/압축 해제 실리콘이 파이프라인에서 병렬로 작동할 수 있습니다. 기본값은 32MiB이며 첫 번째 DirectStorage 팩터리 포인터를 검색할 때 할당됩니다.

타이틀이 메모리에서 메모리로의 압축 해제 작업만을 위해 DirectStorage를 사용하는 경우, 스테이징 버퍼가 필요하지 않으며 SetStagingBufferSize를 호출하여 스테이징 버퍼 크기를 0으로 설정할 수 있습니다. SetStagingBufferSize는 개체나 IDStorageFileX 개체가 없는 IDStorageQueueX 경우에만 호출할 수 있습니다.

DirectStorage의 현재 릴리스는 0 또는 32MiB 스테이징 버퍼 크기만 지원합니다.

CancelRequestsWithTag

DirectStorage는 요청 취소를 지원합니다. 각 요청에는 타이틀 정의 64비트 태그가 연결되어 있습니다. 목적은 취소할 요청에 대한 비트 마스크 역할을 수행하는 것입니다. 타이틀에는 취소를 위한 마스크와 값이 제공됩니다. 큐는 다음 기준과 일치하는 모든 요청을 취소하려고 시도합니다. tag & mask == value

취소는 최선의 작업입니다. 파이프라인에서 요청이 있는 위치에 따라 취소할 수 없는 경우도 있습니다. 예를 들어 취소할 수 없는 하드웨어로 인해 요청이 압축 해제될 수 있습니다. API는 즉시 반환되며 취소된 모든 요청이 처리되도록 기다리는 것을 차단하지 않습니다. 타이틀은 취소된 요청과 관련된 리소스를 해제하기 전에 큐에서 이후 알림이 신호를 받을 때까지 기다려야 합니다.

CancelRequestsWithTag가 호출되는 동시에 큐에 요청을 추가하지 않도록 주의해야 합니다. 이 경우 동작이 정의되지 않습니다. 하지만 CancelRequestsWithTag에 대한 호출이 반환된 후 큐에 추가된 요청은 해당 기준이 일치하더라도 취소되지 않습니다. 이전에 큐에 추가된 요청만 취소됩니다.

GetErrorEvent/RetrieveErrorRecord

읽기로 인해 오류가 발생하는 경우 해당 읽기는 완료된 것으로 표시됩니다. 큐의 이후 알림은 신호 수신에 대해 차단되지 않습니다. 오류 알림은 GetErrorEvent를 사용하여 검색할 수 있는 큐와 연결된 개체를 통해 Event 처리됩니다. 타이틀은 GetErrorEvent에서 반환된 Event 에서 WaitForSingleObject를 사용할 수 있습니다. 이벤트가 신호를 받으면 타이틀은 RetrieveErrorRecord 함수를 호출하여 RetrieveErrorRecord 함수를 마지막으로 호출한 후 첫 번째 오류를 확인할 수 있습니다.

RetrieveErrorRecord에 의해 반환된 오류 레코드에는 마지막 RetrieveErrorRecord 이후 큐에서 처음 실패한 요청에 대한 데이터만 포함됩니다. 오류 레코드의 데이터는 오류가 Event 신호를 받지 않거나 데이터가 이미 검색된 경우 정의되지 않습니다.

쿼리

큐에 대한 정보를 가져옵니다. 여기에는 큐를 만드는 데 사용되는 DSTORAGE_QUEUE_DESC 구조 뿐만 아니라 빈 슬롯의 수와 자동 제출을 트리거하기 위해 큐에 삽입해야 하는 항목의 수가 포함됩니다.

모범 사례

Win32와 동일한 모범 사례가 DirectStorage에도 적용됩니다. 최적의 성능에 대한 임계값이 크게 변경되었습니다.

읽기 크기

회전 디스크에 대한 원래 권장 사항은 최소 128KiB 블록을 읽는 것이었습니다. 블록 크기가 클수록 성능이 계속 증가합니다. 512KiB 크기의 블록이 최고의 성능을 달성했습니다.

NVMe에 이동 부분이 없으면 임계값이 훨씬 낮아집니다. 읽기 성능은 32KiB 읽기로 시작하여 64KiB까지 유지됩니다. 이보다 크게 읽으면 성능이 증가하지 않습니다. 따라서 최적의 성능을 위해 패키지의 데이터를 더 큰 블록으로 병합하는 데 드는 노력이 줄어듭니다.

512KiB를 초과하는 경우 압축 해제를 사용하는 경우 단일 대규모 요청보다 작지만 병렬로 더 많은 요청을 선호합니다. 단일 거대한 요청은 압축 해제를 직렬화하도록 강제하는 반면, 여러 개의 동시 요청은 여러 압축 해제 하드웨어 단위가 병렬로 작동하고 전체 처리량을 달성할 수 있도록 합니다.

Microsoft GDK(게임 개발 키트)의 2022년 10월 릴리스에서는 결합된 원본 및 대상 메모리 사용량을 위해 최대 단일 요청 크기가 대상으로 32MiB에서 1GiB로 증가했습니다. 큰 읽기 크기를 허용하는 다른 스토리지 API에서 쉽게 포팅할 수 있도록 제공됩니다. 그러나 최대 처리량을 달성하기 위한 이전 크기 권장 사항은 여전히 동일하게 유지됩니다. 큰 요청은 여러 압축 해제 하드웨어 단위가 병렬로 작동하도록 허용하지 않기 때문입니다.

Order

이전에는 회전 디스크를 사용하여 디스크에서 읽기 위치를 정렬하는 작업에 시간이 걸렸습니다. 디스크의 순차적 위치에서 읽는 것이 가장 이상적입니다. 이로 인해 디스크 헤드의 최소 이동량이 생성되어 검색 시간이 요소로 제거되었습니다. 이렇게 하면 성능이 크게 향상될 수 있습니다. 위치별로 정렬된 임의 읽기를 제출하는 경우에도 이점이 있었으며 경우에 따라 2배 더 빠릅니다.

NVMe 드라이브에서 읽기 요청을 가능한 순차적으로 명령하는 것도 여전히 유용합니다. NVMe 드라이브는 64KiB 정렬 블록으로 읽습니다. 이로 인해 64KiB 블록에서 사용하지 않는 섹션을 읽는 데 대역폭이 낭비될 수 있습니다. 읽기 요청이 4KiB 전용인 경우 60KiB의 대역폭이 불필요하게 사용됩니다. NVMe는 추가 60KiB를 재사용하여 가능한 경우 보류 중인 다른 요청을 충족합니다. 예를 들어 32KiB에 대한 순차적 읽기와 그 다음 8KiB에 대한 순차적 읽기라는 두 개의 읽기를 가진 경우 드라이브에 여전히 하나의 64KiB 읽기만 있습니다.

큐 관리

회전 디스크에 대한 권장 사항은 큐 크기를 12에서 16 사이로 지정하는 것이었습니다. 더 큰 큐 깊이에는 이점이 없었고 더 작은 큐 깊이를 사용하여 성능이 크게 감소했습니다.

NVMe 사양에 따르면 NVMe 드라이브는 큐당 최대 65,536개 항목 깊이로 여러 개의 큐를 지원해야 합니다. DirectStorage는 이 요구 사항을 지원하므로 타이틀이 한 번에 수천 개의 요청을 제출할 수 있습니다.

이전에는 회전 디스크를 통해 타이틀이 큐 깊이를 12~16 범위로 유지하기 위해 보류 중인 요청을 버퍼링했습니다. DirectStorage에 대한 권장 사항은 요청을 버퍼링하지 않고 요청이 만들어지는 즉시 큐에 넣기하는 것입니다. 전체 시스템은 파이프라인이며 타이틀 버퍼링은 파이프라인에 버블을 생성하여 성능을 심각하게 저하시킬 수 있습니다.

또 다른 권장 사항은 프레임당 생성된 최대 요청 수의 4배 이상의 용량을 가진 큐를 생성하는 것입니다. 이를 통해 충분한 용량을 확보하여 기존 요청이 완료되기를 기다리지 않고 새 요청을 추가할 수 있습니다.

알림 관리

일반적으로 큐에 추가된 알림 요청 수가 적을수록 좋습니다. 권장 사항은 타이틀의 요구 사항과 큐에 있는 알림 요청을 최소로 유지하는 것 사이의 균형을 찾는 것입니다. 각 요청 후 알림을 큐에 추가하면 해당 알림 처리 오버헤드가 증가하여 전반적인 성능이 저하됩니다.

한 가지 예는 콘텐츠를 그룹화하는 것일 수 있습니다. 예를 들어 SFS 텍스처, 지형 요구 사항(예: 메시 및 텍스처) 및 행위자 요구 사항(예: 메시, 텍스처 및 애니메이션)가 있습니다. 이를 통해 단일 알림을 개체를 만드는 데 필요한 모든 자산의 가용성에 바인딩할 수 있습니다.

를 사용하는 ID3D12Fence 것과 상태 배열 중에서 선택하는 것은 타이틀 요구 사항에 따라 달라집니다. GPU에서 데이터를 즉시 사용해야 합니까? 읽기가 완료될 때까지 검사 스레드가 일시 중단될 수 있습니까? 프레임의 특정 지점에서만 데이터를 처리할 수 있어서 정기적인 폴링으로 충분합니까?

고려 사항

동시 요청 수가 훨씬 많을 수 있으므로 타이틀의 다른 부분에 병목 현상이 발생하지 않도록 주의해야 합니다. 타이틀에서 요청을 관리하는 데 드는 비용으로 인해 DirectStorage의 절감 효과가 빠르게 저하될 수 있습니다. 요청당 모든 지원 코드를 확인하고 최소화할 수 있는 항목을 결정하는 것이 좋습니다.

각 요청에 새로운 메모리 블록을 할당해야 합니까?

  • 메모리 시스템에는 새 블록을 찾고 내부 목록을 업데이트하기 위한 오버헤드가 있습니다.
  • 메모리 블록을 최대한 재사용하는 것이 좋습니다.

관리자 업데이트에 잠금이 필요합니까?

  • 더 많은 업데이트가 수행될수록 더 많은 경합이 발생합니다.
  • 최대한의 잠금 해제를 고려하세요.

추론적 로딩이 사용됩니까?

  • 더 많은 요청 생성으로 이어질 수 있는 취소 기능이 지원됩니다.
  • 하지만 메모리를 추론 대상으로 사용할 수 있어야 합니다.
  • 추론 임계값에 대한 엄격한 제한을 고려하세요.

참고 항목

DirectStorage
DirectStorage 사용법 및 내부 상세 정보(NDA 항목)권한 부여 필요
DirectStorage 및 XBTC(NDA 항목)를 사용하여 압축된 콘텐츠 최적화권한 부여 필요
DirectStorage 성능 분석(NDA 항목)권한 부여 필요