Partilhar via


Residência

Um objeto é considerado residente quando é acessível pela GPU.

Orçamento de residência

As GPUs ainda não suportam falhas de página, portanto, os aplicativos devem confirmar dados na memória física enquanto a GPU pode acessá-los. Este processo é conhecido como "tornar algo residente", e deve ser feito tanto para a memória física do sistema quanto para a memória de vídeo física discreta. No D3D12, a maioria dos objetos de API encapsula alguma quantidade de memória acessível por GPU. Essa memória acessível pela GPU é tornada residente durante a criação do objeto da API e removida na destruição do objeto da API.

A quantidade de memória física disponível para o processo é conhecida como o orçamento de memória de vídeo. O orçamento pode flutuar visivelmente à medida que os processos de fundo acordam e dormem; e flutuam drasticamente quando o usuário muda para outro aplicativo. O aplicativo pode ser notificado quando o orçamento é alterado e sondar o orçamento atual e a quantidade de memória consumida atualmente. Se um aplicativo não permanecer dentro de seu orçamento, o processo será intermitentemente congelado para permitir que outros aplicativos sejam executados e/ou as APIs de criação retornarão falha. A interfaceIDXGIAdapter3 dofornece os métodos pertencentes a essa funcionalidade, em particular QueryVideoMemoryInfo e RegisterVideoMemoryBudgetChangeNotificationEvent.

Os aplicativos são incentivados a usar uma reserva para indicar a quantidade de memória que não podem prescindir. Idealmente, as configurações gráficas "baixas" especificadas pelo usuário, ou algo ainda mais baixo, é o valor certo para tal reserva. Definir uma reserva nunca dará a uma candidatura um orçamento mais elevado do que aquele que normalmente receberia. Em vez disso, as informações de reserva ajudam o kernel do sistema operacional a minimizar rapidamente o impacto de grandes situações de pressão de memória. Mesmo a reserva não é garantida para estar disponível para o aplicativo quando o aplicativo não é o aplicativo em primeiro plano.

Recursos de pilha

Embora muitos objetos de API encapsulam alguma memória acessível por GPU, espera-se que os heaps & recursos sejam a maneira mais significativa de os aplicativos consumirem e gerenciarem a memória física. Uma pilha é a unidade de nível mais baixo para gerenciar a memória física, por isso é bom ter alguma familiaridade com suas propriedades de residência.

  • As pilhas não podem ser parcialmente residentes, mas existem soluções alternativas com recursos reservados.
  • As pilhas devem ser orçamentadas como parte de um conjunto específico. Os adaptadores UMA têm um pool, enquanto os adaptadores discretos têm dois pools. Embora seja verdade que o kernel pode deslocar algumas pilhas em adaptadores discretos da memória de vídeo para a memória do sistema, ele faz isso apenas como um último recurso extremo. Os aplicativos não devem confiar no comportamento de orçamento excessivo do kernel e devem se concentrar em um bom gerenciamento de orçamento.
  • As pilhas podem ser removidas da residência, o que permite que seu conteúdo seja paginado para o disco. Mas, a destruição de pilhas é uma técnica mais confiável para liberar residência em todas as arquiteturas de adaptadores. Em adaptadores onde campo de MaxGPUVirtualAddressBitsPerProcess de D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT está perto do tamanho do orçamento, Evict não recuperará a residência de forma confiável.
  • A criação de pilha pode ser lenta; mas é otimizado para processamento de threads em segundo plano. Recomenda-se criar pilhas em threads de plano de fundo para evitar o brilho do thread de renderização. No D3D12, vários threads podem chamar com segurança criar rotinas simultaneamente.

O D3D12 introduz mais flexibilidade e ortogonalidade em seu modelo de recursos, a fim de permitir mais opções para aplicações. Existem três tipos de recursos de alto nível no D3D12: autorizados, colocados e reservados.

  • Os recursos comprometidos criam um recurso e uma pilha ao mesmo tempo. A pilha está implícita e não pode ser acessada diretamente. A pilha é dimensionada adequadamente para localizar todo o recurso dentro da pilha.
  • Os recursos colocados permitem o posicionamento de um recurso em um deslocamento diferente de zero dentro de um heap. Normalmente, as compensações devem estar alinhadas a 64KB; mas existem algumas exceções em ambos os sentidos. Os recursos do MSAA exigem alinhamento de deslocamento de 4 MB e o alinhamento de deslocamento de 4 KB está disponível para texturas pequenas. Os recursos colocados não podem ser realocados ou remapeados para outro heap diretamente; mas permitem a realocação simples dos dados do recurso entre heaps. Depois de criar um novo recurso colocado em uma pilha diferente e copiar os dados do recurso, novos descritores de recursos terão que ser usados para o novo local de dados do recurso.
  • Os recursos reservados só estão disponíveis quando o adaptador suporta recursos lado a lado camada 1 ou superior. Quando disponíveis, oferecem as mais avançadas técnicas de gestão de residências disponíveis; mas nem todos os adaptadores atualmente os suportam. Eles permitem o remapeamento de um recurso sem exigir a regeneração de descritores de recursos, residência parcial de nível mip e cenários de textura esparsa, etc. Nem todos os tipos de recursos são suportados, mesmo quando recursos reservados estão disponíveis, portanto, um gerente de residência baseado em página totalmente geral ainda não é viável.

Prioridades de residência

O Windows 10 Creators Update permite que os desenvolvedores influenciem quais pilhas e recursos serão preferidos para permanecer residentes quando a pressão da memória exigir que alguns de seus recursos sejam rebaixados. Isso ajuda os desenvolvedores a criar aplicativos com melhor desempenho, aproveitando o conhecimento que o tempo de execução não pode inferir do uso da API. Espera-se que os desenvolvedores se tornem mais confortáveis e capazes de especificar prioridades à medida que fazem a transição do uso de recursos comprometidos para recursos reservados e lado a lado.

Aplicar essas prioridades deve ser mais fácil do que gerenciar dois orçamentos de memória dinâmica, rebaixando manualmente e promovendo recursos entre eles, uma vez que os aplicativos já podem fazer isso. Portanto, o design da API de prioridade de residência é grosseiramente granulado com prioridades padrão razoáveis atribuídas a cada heap ou recurso conforme criado. Para obter mais informações, consulte ID3D12Device1::SetResidencyPriority e a enumeração D3D12_RESIDENCY_PRIORITY.

Com prioridades, espera-se que os desenvolvedores:

  • Aumente a prioridade de alguns heaps excecionais para mitigar melhor o impacto de desempenho experimentado desses heaps sendo rebaixados mais cedo ou com mais frequência do que seus padrões de acesso naturais exigiriam. Espera-se que essa abordagem seja aproveitada por aplicativos portados de APIs gráficas, como Direct3D 11 ou OpenGL, cujo modelo de gerenciamento de recursos é significativamente diferente do Direct3D 12.
  • Substitua quase todas as prioridades de heap pelo próprio esquema de bucketização do aplicativo, seja fixo, com base no conhecimento do programador da frequência de acesso, ou dinâmico; Um esquema fixo é mais simples de gerir do que um esquema dinâmico, mas pode ser menos eficaz e exigir a intervenção do programador à medida que os padrões de utilização mudam ao longo do desenvolvimento. Espera-se que essa abordagem seja aproveitada por aplicativos criados com o gerenciamento de recursos no estilo Direct3D 12 em mente, como aqueles que usam a biblioteca de residência (especialmente esquemas dinâmicos).

Algoritmo de prioridade padrão

Um aplicativo não pode especificar prioridades úteis para qualquer heap que tenta gerenciar sem primeiro entender o algoritmo de prioridade padrão. Isso ocorre porque o valor de atribuir uma prioridade específica a uma pilha é derivado de sua prioridade relativa a outras pilhas priorizadas que competem pela mesma memória.

A estratégia escolhida para gerar prioridades padrão é categorizar heaps em dois buckets, favorecendo (dando maior prioridade a) heaps que são assumidos como sendo escritos com frequência pela GPU em vez de heaps que não são.

O bucket de alta prioridade contém heaps e recursos criados com sinalizadores que os identificam como destinos de renderização, buffers de estêncil de profundidade ou UAVs (Exibições de Acesso Não Ordenado). Estes são atribuídos valores de prioridade no intervalo que começa em D3D12_RESIDENCY_PRIORITY_HIGH; para priorizar ainda mais entre esses heaps e recursos, os 16 bits mais baixos da prioridade são definidos para o tamanho do heap ou recurso dividido por 10MB (saturando para 0xFFFF para heaps extremamente grandes). Essa priorização adicional favorece pilhas e recursos maiores.

O bucket de baixa prioridade contém todos os outros heaps e recursos, aos quais é atribuído um valor de prioridade de D3D12_RESIDENCY_PRIORITY_NORMAL. Nenhuma outra priorização entre esses montes e recursos é tentada.

Gestão de residências de programação

Aplicativos simples podem ser capazes de obter simplesmente criando recursos comprometidos até experimentar falhas de falta de memória. Em caso de falha, o aplicativo pode destruir outros recursos comprometidos ou objetos de API para permitir que outras criações de recursos sejam bem-sucedidas. Mas, mesmo aplicativos simples são altamente recomendados para observar alterações de orçamento negativas e destruir objetos de API não utilizados aproximadamente uma vez por quadro.

A complexidade de um projeto de gerenciamento de residência aumentará ao tentar otimizar para arquiteturas de adaptador ou incorporar prioridades de residência. Orçamentar e gerenciar discretamente dois pools de memória discreta será mais complexo do que gerenciar apenas um, e atribuir prioridades fixas em larga escala pode se tornar uma carga de manutenção se os padrões de uso evoluírem. O transbordamento de texturas para a memória do sistema adiciona mais complexidade, pois o recurso errado na memória do sistema pode afetar gravemente a taxa de quadros. Além disso, não há uma funcionalidade simples para ajudar a identificar os recursos que se beneficiariam de maior largura de banda de GPU ou tolerariam menor largura de banda de GPU.

Designs ainda mais complicados consultarão os recursos do adaptador atual. Essas informações estão disponíveis em D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT, D3D12_FEATURE_DATA_ARCHITECTURE, D3D12_TILED_RESOURCES_TIERe D3D12_RESOURCE_HEAP_TIER.

Várias partes de um aplicativo provavelmente acabarão usando técnicas diferentes. Por exemplo, algumas texturas grandes e caminhos de código raramente exercidos podem usar recursos comprometidos, enquanto muitas texturas podem ser designadas com uma propriedade de streaming e usar uma técnica geral de recurso colocado.

ID3D12Pilha

de gerenciamento de memória