> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Visão geral do DirectStorage

> As APIs do DirectStorage para XBOX Series X|S oferecem E/S de armazenamento NVMe de alta taxa de transferência com baixa sobrecarga de CPU para grandes quantidades de solicitações pequenas.

## Introdução

Este artigo fornece uma visão geral das APIs do DirectStorage somente para
consoles XBOX Series X|S. Consulte
[DirectStorage no Desktop](https://aka.ms/directstorage) para obter detalhes sobre o DirectStorage no Desktop.

Os dispositivos de armazenamento NVMe mais recentes conectados por meio de um barramento PCIe podem alcançar níveis
muito altos de taxa de transferência e IOPS (solicitações de E/S por segundo). A sobrecarga das
APIs do Win32 significa que, embora a largura de banda de armazenamento disponível possa ser
utilizada, aproveitá-la pode resultar em uma utilização da CPU inaceitavelmente
alta. Isso é especialmente verdadeiro quando a carga de trabalho consiste em um grande
número de solicitações pequenas.

As APIs do DirectStorage foram projetadas para remover a maior parte da sobrecarga do
sistema operacional, interagindo diretamente com o hardware NVMe subjacente. Isso permite
alcançar uma largura de banda maior com menor uso da CPU. O objetivo é permitir
o processamento de até 50.000 solicitações por segundo usando no máximo 10% de um
único núcleo de CPU.

### Problemas existentes

O conteúdo dos jogos está ficando cada vez maior à medida que a necessidade de ativos de maior resolução
aumenta a cada geração de console. O hardware e o software existentes do XBOX One
têm várias limitações que prejudicam a capacidade dos desenvolvedores de
levar dados do disco rígido para a memória para esse conteúdo de próxima geração.

* Alto uso da CPU
  * As APIs do Win32 existentes podem exigir um núcleo de CPU inteiro em sobrecarga.
  * Isso depende do número de solicitações do título.

* Largura de banda máxima insuficiente do disco
  * Os white papers [Maximizando o desempenho de arquivos no XBOX Series X|S (tópico sob NDA)](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/console-dev/overviews/file-system/Maximizing_File_Performance_Win32_Scarlett) e [Maximizando o desempenho de arquivos no XBOX One (tópico sob NDA)](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/console-dev/overviews/file-system/Maximizing_File_Performance_Win32_Xbox_One) abordam isso em detalhes.

* Incapacidade de priorizar solicitações de disco
  * Sem a capacidade de priorizar as solicitações do título, pode ser difícil criar um
    sistema de streaming responsivo.

* Incapacidade de cancelar solicitações de disco
  * Sem a capacidade de cancelar solicitações, pode ser difícil criar um
    sistema de leitura especulativa.

* Nenhuma descompactação acelerada por hardware
  * Sem a descompactação acelerada por hardware, pode ser necessária uma grande quantidade de recursos
    de CPU para realizar a descompactação em software.

O conjunto de APIs do DirectStorage aborda diretamente cada um desses problemas. O efeito
geral é um aumento drástico no desempenho do sistema de arquivos do XBOX.

### Uso da CPU

O principal objetivo de design do DirectStorage é permitir que um título sustente 50 mil IOPS
usando apenas entre 5% e 10% de um único núcleo de CPU. Isso permite que
o título alcance a largura de banda máxima do subsistema de armazenamento NVMe e, ao
mesmo tempo, permite que a CPU seja usada para outros requisitos do título.

O DirectStorage também adiciona suporte para descompactação por hardware. Cada solicitação de leitura
pode ser roteada diretamente da unidade NVMe para o bloco de descompactação
por hardware interno. Isso elimina a necessidade de um título gastar recursos de CPU
com descompactação.

### Modelo de pipeline enfileirado

O DirectStorage usa um método em lote, no qual várias solicitações são adicionadas a uma fila.
Em um momento posterior, a fila é liberada para o próximo estágio do pipeline. Isso
reduz imediatamente o custo geral de CPU de uma transição entre estágios
do pipeline. No conjunto de APIs do Win32 existente, há uma transição para cada solicitação.
As filas do DirectStorage utilizam algoritmos sem bloqueio para minimizar a contenção.
O título tem controle sobre quando cada fila é liberada.

Em muitos casos com as APIs do Win32, os dados do disco podem precisar ser copiados
para outro buffer. Em alguns casos, os dados podem precisar ser copiados mais de uma vez.
O DirectStorage elimina esse problema mapeando o buffer de destino fornecido pelo título
diretamente em cada camada do pipeline. O hardware grava diretamente no
buffer fornecido pelo título.

Essas alterações contribuem para reduções significativas da sobrecarga de CPU.

### Descompactação

A capacidade do hardware de descompactar dados foi ampliada. Agora ele pode
lidar com uma variedade maior de formatos e em uma velocidade maior do que o subsistema NVMe
consegue fornecer dados. Além disso, o DirectStorage oferece suporte à descompactação no local, o que
elimina a necessidade de gerenciar buffers separados para dados compactados e descompactados.

O hardware oferece suporte a `BCPACK` e `DEFLATE` e fornece a capacidade de aplicar swizzle ao
conteúdo final. Esses formatos não são mutuamente exclusivos. É possível ter
os três aplicados aos dados. Isso dá ao título a capacidade de escolher qual
método oferece a melhor taxa de compactação e o melhor desempenho. Ativos diferentes
podem usar configurações diferentes de compactação e swizzle.

### Profundidade da fila

A recomendação anterior era manter apenas de 12 a 16 solicitações assíncronas
em andamento ao mesmo tempo em uma unidade rotacional. Ir além disso não trazia benefícios de desempenho, e
ficar abaixo disso prejudicava significativamente o desempenho. Isso levava os títulos a
realizar trabalho extra para equilibrar suas solicitações de leitura pendentes e permanecer dentro
da meta recomendada.

Com o objetivo do DirectStorage de permitir que um título alcance 50.000 IOPS, nossa
recomendação mudou. O título não precisa mais tentar equilibrar o
trabalho pendente e a profundidade da fila. O título deve enviar todas as suas solicitações
pendentes. Não há benefício em reter algumas solicitações. Em muitos casos,
reter solicitações pode prejudicar o desempenho, pois o hardware fica parado, aguardando
novas solicitações.

O sistema operacional ainda precisa dividir solicitações de leitura maiores em
várias solicitações menores em alguns casos (por exemplo, ao lidar com a fragmentação do disco).
No entanto, isso foi considerado na arquitetura do DirectStorage. O objetivo de design de 50.000 IOPS
baseia-se na contagem de operações de E/S do título, e não nas solicitações finais
enviadas ao hardware.

### Notificação

Na arquitetura do Win32, uma quantidade significativa de sobrecarga é gasta com
notificações de conclusão de leitura. O título pode sondar uma estrutura *OVERLAPPED*,
aguardar um identificador de Event associado ou realizar uma leitura síncrona
com bloqueio. No geral, isso aumenta a demanda de recursos de cada solicitação
de leitura.

O DirectStorage mantém os dois conceitos assíncronos de notificações e também
adiciona um terceiro método. Não há suporte para leituras síncronas com bloqueio no
DirectStorage. É possível que um título implemente seu próprio sistema. No entanto,
isso não é recomendado.

O primeiro método assíncrono é implementado por meio de um bloco de status que é definido
quando as solicitações associadas são concluídas. O título pode sondar o bloco conforme
necessário para determinar quando as leituras foram concluídas. Isso é semelhante ao método do Win32 de
sondar uma estrutura *OVERLAPPED* para verificar a conclusão.

O segundo método assíncrono usa um objeto `Event` do Windows para sinalizar a conclusão.
Isso é semelhante a usar uma estrutura *OVERLAPPED* com um objeto `Event` correspondente.
O título pode usar o método [WaitForSingleObject](https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject)
para fazer com que o thread de chamada seja suspenso até que as operações de leitura sejam concluídas.

O terceiro método assíncrono é implementado usando um [ID3D12Fence](https://learn.microsoft.com/windows/win32/api/d3d12/nn-d3d12-id3d12fence). O título
pode suspender aguardando o fence ou sondar o fence, se necessário.
Há também o benefício de que a GPU pode usar o fence para notificação direta
de solicitações concluídas.

O sistema de notificação do DirectStorage não está vinculado a uma única solicitação de leitura. Ele é
uma entrada colocada na fila, que é sinalizada quando todas as solicitações de leitura
anteriores tiverem sido concluídas. Isso dá ao título controle sobre a granularidade
necessária para a notificação. A notificação é sempre sinalizada na ordem da fila.
A fila pode ser considerada uma fila FIFO (primeiro a entrar, primeiro a sair). O título só
precisa consultar a última notificação relevante. Há garantia de que todas as solicitações enfileiradas anteriormente
foram concluídas.

### Descompactação de memória para memória

O DirectStorage fornece um tipo de fila para invocar o hardware de descompactação com
a origem da descompactação sendo a memória em vez de um arquivo em disco. Isso permite que o
hardware de descompactação seja utilizado se o ativo compactado não for proveniente
de um arquivo ou tiver sido obtido anteriormente e mantido na memória como cache. Uma
fila com origem em memória só aceita solicitações com origem em memória, e uma fila com origem em arquivo
só aceita solicitações com origem em arquivo.

Se nenhuma opção de descompactação for especificada em uma solicitação com origem em memória, o
hardware de descompactação também pode atuar como um mecanismo de cópia DMA.

Embora o DirectStorage garanta que as notificações de conclusão estejam em ordem,
o DirectStorage não oferece garantia sobre quando as solicitações começam a ser processadas.
Como resultado, não deve haver dependências de dados entre solicitações pendentes. Ou
seja, o destino da solicitação A não pode ser usado como origem da solicitação B, a menos que a solicitação
B seja enfileirada após a conclusão da solicitação A.

As filas com origem em memória devem ser criadas com prioridade em tempo real. Além disso,
as solicitações em tempo real com origem em memória são sempre processadas pelo hardware de
descompactação antes das solicitações com origem em disco que exigem descompactação.
Se as filas com origem em disco não tiverem nenhuma solicitação de descompactação, os dois
tipos de fila são processados de forma totalmente paralela, sem afetar o outro tipo.

### Prioridade

O DirectStorage permite que um nível de prioridade seja atribuído a cada fila. Cada entrada
da fila herda a prioridade da fila. Quatro níveis de prioridade diferentes são
fornecidos: tempo real, alta, normal e baixa. As solicitações são processadas em um esquema
round-robin ponderado. Por exemplo, processar X solicitações com prioridade alta antes de processar
uma solicitação com prioridade normal. Processar Y solicitações com prioridade normal antes de
processar uma solicitação com prioridade baixa.

A ponderação de prioridade é calculada com base no tamanho de cada solicitação. A ponderação padrão
entre cada prioridade é de aproximadamente 10x. Isso significa que, para cada 1 KB de solicitação
de prioridade baixa, 10 KB de solicitação de prioridade média e 100 KB de solicitação de prioridade alta
teriam sido processados.

As solicitações de leitura existentes do Win32 são roteadas pelo mesmo sistema de prioridade. Todas
as solicitações do Win32 são consideradas de prioridade normal.

As filas com origem em memória devem ser criadas com prioridade em tempo real.

### Cancelamento

Cada solicitação de leitura do DirectStorage tem uma máscara de 64 bits fornecida pelo título associada
a ela. Isso serve para oferecer suporte ao cancelamento de solicitações de leitura pendentes. O título pode
cancelar solicitações que correspondam a um conjunto específico de sinalizadores dentro da máscara.

Mesmo com suporte para cancelamento, ainda é possível que uma solicitação de leitura seja
processada pelo hardware. A solicitação de cancelamento do título é uma tentativa de
melhor esforço. Se a solicitação já estiver sendo processada ativamente pelo hardware, ela
não poderá ser cancelada.

Como a solicitação de cancelamento é de melhor esforço, o título deve aguardar até
ser notificado de que o processamento da solicitação de leitura foi concluído. O título
não pode liberar nenhum recurso necessário até que uma notificação posterior na fila seja
recebida. No entanto, durante esse período, novas solicitações que correspondam a sinalizadores
usados em uma solicitação de cancelamento anterior podem ser enfileiradas e não serão canceladas.

Quando uma solicitação cancelada é concluída, ela é considerada um **sucesso**, mesmo que
tenha sido cancelada e não tenha produzido o resultado completo. Em outras palavras, se
houver tentativa de cancelamento em uma solicitação, o título não poderá mais consumir o
resultado da solicitação possivelmente cancelada após a conclusão.

### Garantia

Os consoles XBOX One e XBOX One S tinham uma garantia mínima de 40 MB/s. O
console XBOX One X aumentou a garantia mínima para 60 MB/s. Esses números estão
bem abaixo dos limites reais do hardware, que ficam na faixa de 130 MB/s. Isso se devia
inteiramente à sobrecarga causada pelo sistema operacional.

O DirectStorage remove a maior parte da sobrecarga causada pelo sistema operacional. Isso
permite uma garantia mínima mais próxima dos limites do hardware. A nova garantia mínima
de desempenho é de 2,0 GB/s em uma janela de 250 ms para dados brutos. O uso de
descompactação no conteúdo aumentará ainda mais a largura de banda final.

Os futuros consoles XBOX oferecerão suporte à adição de unidades dinâmicas instaláveis pelo usuário
que também são baseadas em NVMe. A mesma garantia mínima de desempenho
fornecida para a unidade interna também é fornecida para a unidade instalável pelo usuário.

## Visão geral da API

As interfaces do DirectStorage seguem o mesmo padrão das interfaces do Direct3D.
Inicialmente, o título obtém uma fábrica singleton. A fábrica é usada para criar
filas de solicitações e abrir arquivos; cada um desses objetos tem um mapeamento
direto para o hardware. Em seguida, solicitações individuais são enfileiradas em uma fila para
serem enviadas ao hardware.

### IDStorageFactoryX

`IDStorageFactoryX` é a interface principal para criar filas, abrir arquivos e
enviar solicitações pendentes.

O objeto `IDStorageFactoryX `tem os seguintes métodos.

* [OpenFile](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_openfile)
  * Cria um objeto `IDStorageFileX `, que representa um arquivo.

* [CreateQueue](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_createqueue)
  * Cria um objeto `IDStorageQueueX`. Usado para criar solicitações de leitura.

* [CreateStatusArray](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_createstatusarray)
  * Cria um objeto `IDStorageStatusArray`, que gerencia os sinalizadores de status
    de conclusão.

* [SetCPUAffinity](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_setcpuaffinity)
  * Restringe o trabalho do DirectStorage fora do thread de chamada a um conjunto de núcleos
    de CPU definido pelo título.
  * **OBSERVAÇÃO** O DirectStorage tenta fazer a maior parte do trabalho no
    thread de chamada. O trabalho fora do thread de chamada só ocorre quando não pode ser
    feito no thread de chamada. Veja alguns exemplos a seguir.
    * O pipeline de recursos subjacente está cheio durante `IDStorageQueueX::Submit`,
      e nem todas as solicitações da fila podem ser encaminhadas. As solicitações
      restantes serão processadas mais tarde, quando os recursos forem liberados, e isso é
      feito em um thread de trabalho do DirectStorage.
    * Processamento da conclusão de solicitações em `ID3DFence` ou `IDStorageStatusArray`.

* [SetDebugFlags](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_setdebugflags)
  * Controla se o DirectStorage fará validações adicionais no momento do
    enfileiramento da solicitação para auxiliar na depuração.

* [SetStagingBufferSize](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_setstagingbuffersize)
  * Define o tamanho do buffer de preparo usado para armazenar temporariamente o conteúdo carregado
    do dispositivo de armazenamento antes de ser descriptografado/descompactado. Se forem usadas
    apenas filas com origem em memória, o buffer de preparo pode ter tamanho 0.

### IDStorageFactoryX1

A interface `IDStorageFactoryX1` estende a interface `IDStorageFactoryX` com
um método [GetStats](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX1/methods/idstoragefactoryx1_getstats).

* [GetStats](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX1/methods/idstoragefactoryx1_getstats)
  * Obtém as estatísticas do DirectStorage. Essa função pode ser usada para integrar
    o DirectStorage a pipelines de diagnóstico e telemetria existentes.
    Ela faz um processamento mínimo e, portanto, pode ser chamada com frequência. As estatísticas
    não incluem operações de E/S de arquivo do Win32.

### IDStorageFactoryX2

A interface `IDStorageFactoryX2` estende a interface \`IDStorageFactoryX1 com
um método [CreateQueue1](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX2/methods/idstoragefactoryx_createqueue1).

* [CreateQueue1](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX2/methods/idstoragefactoryx_createqueue1)
  * Cria um objeto `IDStorageQueueX2`. Usa uma nova estrutura para permitir
    opções adicionais na criação da fila, incluindo a capacidade de substituir
    o recurso de envio automático de uma fila.

### IDStorageFileX

Todos os arquivos precisam ser abertos inicialmente pelo DirectStorage por meio do
objeto `IDStorageFactoryX`. Isso equivale a usar `CreateFile` nas interfaces de API
do Win32.

Os arquivos são abertos com a permissão `FILE_SHARED_READ`. Se necessário, os títulos podem
abrir o arquivo simultaneamente usando as APIs do Win32, desde que as permissões
adequadas sejam respeitadas. Durante o desenvolvimento, há suporte para implantações soltas e empacotadas.

Os arquivos são fechados chamando explicitamente a função [Close](/pt-BR/reference/system/dstorage/interfaces/IDStorageFileX/methods/idstoragefilex_close)
no objeto de arquivo ou quando a última referência ao objeto
`IDStorageFileX` correspondente é liberada. No entanto, todas as operações de E/S pendentes devem
ser concluídas antes que o arquivo possa ser fechado. Isso significa que ambos os métodos de fechar
um arquivo ficarão bloqueados até que todas as operações de E/S pendentes nesse arquivo sejam concluídas.

O jogo pode obter um identificador do Win32 para um arquivo representado por um objeto `IDStorageFileX`
chamando a função [GetHandle](/pt-BR/reference/system/dstorage/interfaces/IDStorageFileX/methods/idstoragefilex_gethandle).
O identificador é aberto com permissões `GENERIC_READ` e modo de compartilhamento `FILE_SHARE_READ`.
Ele pode ser usado para consultar o tamanho do arquivo e assim por diante. O identificador deve ser fechado
com `CloseHandle()` quando não for mais necessário.

### IDStorageQueueX

As solicitações de leitura são enviadas ao NVMe por meio de um objeto `IDStorageQueueX`.
No entanto, as solicitações não são enviadas ao dispositivo até que o título chame
[Submit](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_submit) na fila, ou até que um dos métodos Enqueue
tenha preenchido mais da metade da capacidade da fila desde o último envio e dispare
um envio automático. Os envios são tratados como uma única transição para o
próximo estágio do pipeline. Isso permite que o título controle quando ocorre o custo de CPU
da transição entre o título e o kernel.

Os objetos `IDStorageQueueX` têm quatro propriedades.

* [SourceType](/pt-BR/reference/system/dstorage/enums/dstorage_request_source_type)
  * Especifica se a fila pode receber solicitações com origem em arquivo ou
    solicitações com origem em memória.

* [Priority](/pt-BR/reference/system/dstorage/enums/dstorage_priority)
  * A prioridade de todas as solicitações enviadas à fila: tempo real, alta, normal ou baixa.
  * As filas com origem em memória devem ser criadas com prioridade em tempo real.
  * As solicitações são processadas em uma ordem round-robin ponderada com base na prioridade.
  * As solicitações do Win32 são processadas no nível de prioridade normal.

* **Capacity**
  * O número máximo de solicitações pendentes que a fila pode conter.
  * Tentar enfileirar uma solicitação quando a fila está em sua capacidade máxima ficará bloqueado
    até que as entradas sejam concluídas pelo hardware.
  * A quantidade de memória necessária para uma fila é aproximadamente a capacidade da fila
    multiplicada pelo tamanho de um `DSTORAGE_REQUEST`.

* **Name**
  * Serve apenas para auxiliar na depuração. O nome não é usado por nenhuma parte do
    código do DirectStorage, mas é visível nas ferramentas do desenvolvedor, como o
    [PIX (tópico sob NDA)](/pt-BR/tools/tools-console/pix/pix-directstorage).

O hardware processa as solicitações de forma assíncrona para alcançar a maior
taxa de transferência. No entanto, ao contrário do Win32, o título é notificado da conclusão na ordem
FIFO. Na notificação de conclusão, há garantia de que todas as solicitações anteriores
para a mesma fila também foram concluídas.

### IDStorageQueueX1

A interface `IDStorageQueueX1` estende a interface `IDStorageQueueX` com o
método [EnqueueSetEvent](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX1/methods/idstoragequeuex_enqueuesetevent).

### IDStorageQueueX2

A interface `IDStorageQueueX2` estende a interface \`IDStorageQueueX1 com o método [CreateQueue1](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX2/methods/idstoragefactoryx_createqueue1).

E uma propriedade adicional.

* [Options](/pt-BR/reference/system/dstorage/structs/dstorage_queue_options)
  * Sinalizadores usados para controlar o comportamento da fila, incluindo a desativação do envio automático.

### EnqueueRequest

Essa interface é funcionalmente igual à interface `ReadFile` do Win32.
Solicitações de leitura individuais são criadas e enviadas à fila. A principal
diferença é que o DirectStorage permite que muitas solicitações sejam enfileiradas antes do
envio, oferece suporte à descompactação por hardware e oferece suporte ao cancelamento.

As solicitações têm várias propriedades principais.

**Origem da solicitação**
Dependendo da combinação de `Options.SourceType` e
`Options.SourceIsPhysicalPages`, o DirectStorage usa um dos três
grupos de propriedades a seguir para especificar onde os dados de origem estão.

* **File** e **FileOffset**
  * Este grupo é usado quando `Options.SourceType` é `DSTORAGE_REQUEST_SOURCE_FILE`
  * **File** é aberto previamente com `IDStorageFactoryX::OpenFile`.
  * **FileOffset** precisa estar alinhado a 16 bytes se a descompactação for usada, ou
    não tem requisito de alinhamento se a descompactação não for usada.
    * Essa é uma grande mudança em relação ao Win32, que exigia alinhamento de 4 KiB dentro
      do arquivo para leituras assíncronas.

* **Source**
  * Este grupo é usado quando `Options.SourceType` é `DSTORAGE_REQUEST_SOURCE_MEMORY`
    e `Options.SourceIsPhysicalPages` é `FALSE`.
  * O buffer de memória que contém os dados a serem descompactados.

* **SourcePageArray** e **SourcePageOffset**
  * Este grupo é usado quando `Options.SourceType` é `DSTORAGE_REQUEST_SOURCE_MEMORY`
    e `Options.SourceIsPhysicalPages` é `TRUE`.
  * Semelhante a `Source`, mas fornece o buffer de memória de origem na forma de uma
    matriz de páginas físicas de 64 KB e o deslocamento em bytes na primeira página.
  * Páginas físicas de 64 KB podem ser alocadas por `XMemAllocatePhysicalPages`.

**SourceSize**

* Tamanho, em bytes, dos dados de origem a serem lidos, seja de um buffer de memória
  ou de um arquivo.

**IntermediateSize**

* Quando a descompactação `zlib` e `BCPACK`estão habilitadas nesta solicitação,
  `IntermediateSize` é usado para especificar o tamanho intermediário para o qual os dados
  de origem são descompactados com zlib (e a partir do qual são descompactados com BCPACK).
* Caso contrário, deve ser definido como 0.

**Destino da solicitação**
Dependendo de `Options.DestinationIsPhysicalPages`, o DirectStorage usa um dos
dois grupos de propriedades a seguir para especificar onde o destino está.

* **Destination**
  * Este grupo é usado quando `Options.DestinationIsPhysicalPages` é `FALSE`.
  * O buffer de destino para os dados carregados finais.
  * A descompactação ocorre usando buffers internos compartilhados e pode ser considerada
    no local.

* **DestinationPageArray** e **DestinationPageOffset**
  * Este grupo é usado quando `Options.DestinationIsPhysicalPages` é `TRUE`.
  * Semelhante a `Destination`, mas fornece o buffer de memória de destino na
    forma de uma matriz de páginas físicas de 64 KB e o deslocamento em bytes na primeira
    página.
  * Páginas físicas de 64 KB podem ser alocadas por `XMemAllocatePhysicalPages`.

**DestinationSize**

* Tamanho esperado, em bytes, do conteúdo carregado final. O destino deve
  conter espaço suficiente para acomodar a operação.
* O tamanho deve ser igual a **SourceSize** quando a descompactação não for usada, ou
  maior que **SourceSize** quando a descompactação for usada.

**CancellationTag**

* Uma marca arbitrária de 64 bits definida pelo título.
* Essa marca é usada como máscara para solicitações de cancelamento.

**Name**

* Cadeia de caracteres opcional para auxiliar na depuração. O Name pode aparecer nas
  ferramentas do desenvolvedor, como o [PIX (tópico sob NDA)](/pt-BR/tools/tools-console/pix/pix-directstorage), ou no registro de erro
  obtido de `IDStorageQueueX::RetrieveErrorRecord`. A cadeia de caracteres `Name` precisa
  estar acessível durante todo o tempo de vida da solicitação.

**Options**

* **ZlibDecompress**
  * Indica que os dados precisam ser descompactados usando o padrão de
    descompactação RFC 1950.
* **BcpackMode**
  * Indica qual modo de `BCPACK` deve ser usado para descompactar os dados.
  * None é uma opção válida e significa que os dados não estão compactados com `BCPACK`.
* **SwizzleMode**
  * Indica como o swizzle deve ser aplicado aos dados finais na memória.
* **DestinationIsPhysicalPages**
  * Indica que o buffer de destino é especificado usando
    **DestinationPageArray** e **DestinationPageOffset** em vez de
    **Destination**.
* **SourceType**
  * Uma solicitação pode ter origem em memória e, portanto, ter as propriedades `Source`/
    `SourcePageArray` e `SourcePageOffset`, ou ter origem em arquivo e, portanto,
    ter as propriedades `File`/`FileOffset`.
* **SourceIsPhysicalPages**
  * Indica que o buffer de origem é especificado usando **SourcePageArray**
    e **SourcePageOffset** em vez de **Source**.

### EnqueueStatus/EnqueueSignal/EnqueueSetEvent

As solicitações podem ser enfileiradas e tratadas como uma série de solicitações relacionadas. Isso é
feito enfileirando uma notificação para quando o processamento atingir um determinado ponto
da fila. As notificações são processadas somente quando todas as solicitações de leitura anteriores
forem concluídas. Isso garante que os dados de todas as solicitações anteriores estejam imediatamente
disponíveis.

O título tem dois métodos de sondagem e um método de espera para notificação. O
título pode inserir um objeto `ID3D12Fence`, um objeto `IDStorageStatusArrayX` ou uma
operação de definição de evento. O `ID3D12Fence` se comporta como esperado para um objeto
`ID3D12Fence`. Um thread do título pode aguardar um `Event`, a CPU pode sondar o fence e a
GPU pode sondar o fence. O objeto `IDStorageStatusArrayX` permite a sondagem da
conclusão pela CPU e o acesso a possíveis falhas de leitura. O método `EnqueueSetEvent`
permite que um thread do título aguarde o evento especificado em vez de fazer sondagem.
Isso difere de `ID3D12Fence::SetEventOnCompletion`, pois a implementação do XBOX
de `ID3D12Fence::SetEventOnCompletion` fica em espera ativa no fence até que ele seja sinalizado,
consumindo assim o thread de hardware da CPU até o sinal, enquanto `EnqueueSetEvent`
permite que o thread do título use `WaitForSingleObject`/`WaitForMultipleObjects` para
ceder a CPU a outros threads até que o evento seja sinalizado.

Como mencionado anteriormente, todas as solicitações são concluídas em ordem, mesmo que o hardware
subjacente decida reordená-las para obter desempenho. As notificações não são sinalizadas
até que todas as solicitações enfileiradas anteriormente na fila tenham sido concluídas.

### Descompactação

A descompactação é feita por hardware dedicado. Isso remove a sobrecarga de CPU
dos algoritmos de descompactação tradicionais. O DirectStorage aloca um bloco fixo
de memória durante a inicialização para usar como buffer de trabalho para a descompactação.
Isso permite a descompactação no local e elimina a necessidade de manter os dados
compactados e descompactados na memória ao mesmo tempo.

O hardware de descompactação oferece suporte a três modos de operação. Os modos não são
mutuamente exclusivos, portanto, qualquer combinação de modos pode ser especificada. Os modos
de descompactação são aplicados na seguinte ordem: `DEFLATE`, `BCPACK` e `Swizzle`.

* `ZLibDecompress`
  * Este é o padrão de compactação [IETF RFC 1950](https://www.ietf.org/rfc/rfc1950.txt).

* `BCPack`
  * `BCPack` é um codificador de entropia personalizado projetado especificamente para dados BCn.
    Em geral, isso significa que os pontos de extremidade de cor são separados dos
    índices da paleta (ou seja, pesos) e compactados usando um algoritmo rANS.

* `Swizzle`
  * Os modos `Swizzle` e de embaralhamento podem oferecer otimizações adicionais em pipelines de conteúdo.

Quando dados de alta entropia são compactados, é possível que a compactação
na verdade aumente o tamanho. Por outro lado, a descompactação correspondente reduzirá
o tamanho. O DirectStorage não permite descompactação com redução de tamanho, e cabe ao
título detectar dados de alta entropia que não são compactáveis e evitar
compactar esses ativos. Para obter mais detalhes, consulte o guia [Otimizando
conteúdo compactado usando DirectStorage e XBTC (tópico sob NDA)](/pt-BR/build/console-features/storage/directstorage/directstorage-compression).

### Buffer de preparo

Internamente, o DirectStorage usa um buffer para preparar todo o conteúdo lido do armazenamento
NVMe bruto antes de realizar operações como descriptografia e
descompactação. Esse buffer de preparo permite que a unidade NVMe e o silício de descriptografia/descompactação trabalhem em um pipeline em paralelo. Seu tamanho padrão é de 32 MiB
e ele é alocado quando o primeiro ponteiro de fábrica do DirectStorage é recuperado.

Se um título usar o DirectStorage apenas para operações de descompactação de memória para memória,
o buffer de preparo não é necessário, e
[SetStagingBufferSize](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_setstagingbuffersize) pode ser chamado
para definir o tamanho do buffer de preparo como 0.

A versão atual do DirectStorage oferece suporte a tamanhos de buffer de preparo de 0, 16, 20, 24, 28 e 32 MiB. Um tamanho menor que o padrão economizará memória para o título, mas pode afetar o desempenho geral de leitura.

**OBSERVAÇÃO:** [SetStagingBufferSize](/pt-BR/reference/system/dstorage/interfaces/IDStorageFactoryX/methods/idstoragefactoryx_setstagingbuffersize)
só pode ser chamado quando não existir nenhum objeto `IDStorageQueueX` nem `IDStorageFileX`; caso contrário, ele gerará um erro.

### CancelRequestsWithTag

O DirectStorage oferece suporte ao cancelamento de solicitações. Cada solicitação tem uma marca
de 64 bits definida pelo título associada a ela. A finalidade é servir como uma máscara de bits para
indicar quais solicitações cancelar. O título fornece uma máscara e um valor para o
cancelamento. A fila tentará cancelar todas as solicitações que correspondam ao
critério: `tag & mask == value`.

O cancelamento é uma operação de melhor esforço. Dependendo de onde a solicitação está
no pipeline, talvez não seja possível cancelá-la. Por exemplo, a solicitação pode
estar sendo descompactada pelo hardware, o que não pode ser cancelado. A API
retorna imediatamente e não fica bloqueada aguardando o processamento de todas as solicitações canceladas.
Os títulos devem aguardar até que uma notificação posterior na fila seja sinalizada
antes de liberar os recursos associados às solicitações canceladas.

É preciso ter cuidado para evitar adicionar solicitações a uma fila ao mesmo tempo em que
[CancelRequestsWithTag](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_cancelrequestswithtag) está sendo chamado.
Nesse caso, o comportamento é indefinido. No entanto, as solicitações adicionadas à fila
depois que a chamada para [CancelRequestsWithTag](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_cancelrequestswithtag)
tiver retornado não serão canceladas, mesmo que correspondam aos critérios. Somente as solicitações
enfileiradas anteriormente serão canceladas.

### GetErrorEvent/RetrieveErrorRecord

Se uma leitura causar um erro, essa leitura será marcada como concluída. As notificações
futuras na fila não são impedidas de ser sinalizadas. A notificação de erros
é tratada por meio de um objeto `Event` associado à fila, que pode ser
recuperado com [GetErrorEvent](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_geterrorevent). O título pode
usar **WaitForSingleObject** no `Event` retornado por
[GetErrorEvent](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_geterrorevent). Se o evento for sinalizado,
o título poderá obter o primeiro erro desde a última chamada à
função [RetrieveErrorRecord](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_retrieveerrorrecord)
chamando a função [RetrieveErrorRecord](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_retrieveerrorrecord).

O registro de erro retornado por
[RetrieveErrorRecord](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_retrieveerrorrecord) contém apenas dados
da primeira solicitação com falha na fila desde a última chamada a
[RetrieveErrorRecord](/pt-BR/reference/system/dstorage/interfaces/IDStorageQueueX/methods/idstoragequeuex_retrieveerrorrecord). Os dados no
registro de erro são indefinidos se o `Event` de erro não estiver sinalizado ou se os dados já
tiverem sido recuperados.

### Query

Obtém informações sobre a fila. Isso inclui as estruturas [DSTORAGE\_QUEUE\_DESC](/pt-BR/reference/system/dstorage/structs/dstorage_queue_desc) ou [DSTORAGE\_QUEUE\_DESC1](/pt-BR/reference/system/dstorage/structs/dstorage_queue_desc1)
usadas na criação da fila, bem como o número de slots vazios
e o número de entradas que precisam ser enfileiradas para disparar o envio
automático.

## Práticas recomendadas

As mesmas práticas recomendadas indicadas para o Win32 também se aplicam ao DirectStorage.
Os limites para o desempenho ideal mudaram radicalmente.

### Tamanhos de leitura

A recomendação original para um disco rotacional era ler em blocos de pelo menos 128 KiB.
O desempenho continua aumentando com tamanhos de bloco maiores. Blocos de 512
KiB alcançavam o melhor desempenho.

A ausência de partes móveis no NVMe cria um limite muito menor. O desempenho
de leitura dá um grande salto a partir de leituras de 32 KiB e começa a atingir o máximo
com 64 KiB. Ler mais do que isso não aumenta o desempenho. Isso significa
que é necessário menos esforço para mesclar dados em blocos maiores no
pacote para obter o desempenho ideal.

Acima de 512 KiB, se a descompactação for usada, prefira mais solicitações menores em
paralelo a uma única solicitação enorme. Uma única solicitação enorme forçará a
descompactação a ser serializada, enquanto várias solicitações simultâneas permitem que
várias unidades de hardware de descompactação trabalhem em paralelo e alcancem a taxa de transferência
máxima.

Na versão de outubro de 2022 do Microsoft Game Development Kit (GDK), o tamanho máximo de uma única solicitação
foi aumentado de 32 MiB como destino para 1 GiB de uso combinado de memória (origem mais
destino). Isso é fornecido para facilitar a portabilidade de outras APIs de armazenamento
que permitem tamanhos de leitura grandes. Mas a recomendação de tamanho anterior para alcançar
a taxa de transferência máxima continua a mesma, porque solicitações grandes não permitem que
várias unidades de hardware de descompactação trabalhem em paralelo.

### Ordem

Anteriormente, com discos rotacionais, havia um esforço para ordenar o local das
leituras no disco. A situação ideal era ler de locais sequenciais no
disco. Isso gerava a quantidade mínima de movimento da cabeça do disco, o que
eliminava o tempo de busca como fator. Fazer isso podia aumentar o desempenho em uma ordem
de grandeza. Havia até benefício em enviar leituras aleatórias classificadas por
local e, em alguns casos, elas eram 2x mais rápidas.

Ainda é útil ordenar as solicitações de leitura para que sejam o mais sequenciais possível em uma
unidade NVMe. A unidade NVMe lê em blocos alinhados a 64 KiB. Por causa disso,
pode haver desperdício de largura de banda lendo seções não usadas de um bloco de 64 KiB. Se uma
solicitação de leitura for de apenas 4 KiB, haverá 60 KiB de largura de banda desperdiçada. O
NVMe reutilizará esses 60 KiB extras para atender a outras solicitações pendentes, se possível.
Por exemplo, se você tiver duas leituras sequenciais, uma de 32 KiB seguida por outra de 8 KiB,
ainda haverá apenas uma leitura de 64 KiB da unidade.

### Gerenciamento de filas

A recomendação com discos rotacionais era ter um tamanho de fila entre 12 e
16\. Não havia benefício com uma profundidade de fila maior, e a redução de
desempenho decorrente do uso de profundidades de fila menores era significativa.

A especificação NVMe diz que uma unidade NVMe deve oferecer suporte a várias filas com uma
profundidade de até 65.536 entradas por fila. O DirectStorage oferece suporte a esse requisito,
permitindo assim que o título envie milhares de solicitações de uma só vez.

Anteriormente, com discos rotacionais, os títulos armazenavam em buffer as solicitações pendentes para manter uma
profundidade de fila na faixa de 12 a 16. A recomendação para o DirectStorage é
não armazenar solicitações em buffer, mas enfileirá-las assim que forem criadas. Todo o
sistema é um pipeline, e o armazenamento em buffer pelo título criará bolhas no pipeline,
o que pode prejudicar seriamente o desempenho.

Outra recomendação é criar uma fila com capacidade de pelo menos quatro vezes
o maior número de solicitações criadas por quadro. Isso deve permitir capacidade
suficiente para que novas solicitações possam ser adicionadas sem paralisação, aguardando a conclusão
das solicitações existentes.

### Gerenciamento de notificações

Em geral, quanto menos solicitações de notificação forem adicionadas à fila, melhor. A
recomendação é encontrar um equilíbrio entre as necessidades do título e manter as solicitações
de notificação enfileiradas no mínimo. Enfileirar uma notificação após cada solicitação
só prejudicará o desempenho geral devido ao aumento da sobrecarga de processamento
dessas notificações.

Um exemplo pode ser o agrupamento por conteúdo. Por exemplo, texturas SFS, necessidades
de terreno (por exemplo, malha e textura) e necessidades de atores (por exemplo, malha,
textura e animação). Isso permite que uma única notificação seja vinculada à
disponibilidade de todos os ativos necessários para criar um objeto.

A escolha entre usar um `ID3D12Fence` ou uma matriz de status depende
das necessidades do título. Os dados precisam ser usados imediatamente pela GPU? É
aceitável que o thread de verificação seja suspenso até que as leituras sejam concluídas? A sondagem
periódica é suficiente porque os dados só podem ser processados em determinados pontos
do quadro?

### Considerações

Com a possibilidade de um número muito maior de solicitações em andamento, é preciso
ter cuidado para evitar a criação de gargalos em outras partes do título. Os custos
para o título gerenciar as solicitações podem rapidamente superar a economia
obtida pelo DirectStorage. A recomendação é examinar todo o código de suporte
por solicitação e determinar o que pode ser minimizado.

Cada solicitação exige a alocação de um novo bloco de memória?

* O sistema de memória tem sobrecarga para encontrar um novo bloco e atualizar listas internas.
* Considere reutilizar blocos de memória o máximo possível.

É necessário um bloqueio para atualizar os gerenciadores?

* Cria mais contenção à medida que mais atualizações são realizadas.
* Considere evitar bloqueios o máximo possível.

O carregamento especulativo é usado?

* Há suporte para cancelamento, o que pode levar à criação de mais solicitações.
* No entanto, é preciso haver memória disponível para a especulação.
* Considere limites rígidos para os limiares de especulação.

## Confira também

[DirectStorage](/pt-BR/build/console-features/storage/directstorage-toc)
[Uso e detalhes internos do DirectStorage (tópico sob NDA)](/pt-BR/build/console-features/storage/directstorage/directstorage-white-paper)
[Otimizando conteúdo compactado usando DirectStorage e XBTC (tópico sob NDA)](/pt-BR/build/console-features/storage/directstorage/directstorage-compression)
[Analisando o desempenho do DirectStorage (tópico sob NDA)](/pt-BR/tools/tools-console/pix/pix-directstorage)


## Related topics

- [Visão geral do XBOX Series X|S](/pt-BR/paths/series-xs/overview.md)
- [Visão geral do Unreal Engine](/pt-BR/paths/unreal/overview.md)
- [Visão geral do Play Anywhere (Console + PC)](/pt-BR/paths/play-anywhere/overview.md)
- [Portar do PC (não-Steam)](/pt-BR/paths/porting/from-pc.md)
- [Visão geral do Unity](/pt-BR/paths/unity/overview.md)
