Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O recurso de passagem de renderização é novo para o Windows 10, versão 1809 (10.0; Build 17763) e apresenta o conceito de uma passagem de renderização do Direct3D 12. Um passe de renderização consiste em um subconjunto dos comandos que você registra em uma lista de comandos.
Para declarar onde cada passagem de renderização começa e termina, aninha os comandos que pertencem a essa passagem dentro de chamadas para ID3D12GraphicsCommandList4::BeginRenderPass e EndRenderPass. Consequentemente, qualquer lista de comandos contém zero, um ou mais passes de renderização.
Cenários
Os passes de renderização podem melhorar o desempenho do renderizador se ele for baseado em Tile-Based TBDR (Renderização Adiada), entre outras técnicas. Mais especificamente, a técnica ajuda o renderizador a melhorar a eficiência da GPU, reduzindo o tráfego de memória de/para a memória fora do chip, permitindo que seu aplicativo identifique melhor os requisitos de ordenação de renderização de recursos e as dependências de dados.
Um driver de exibição escrito expressamente para aproveitar o recurso de passes de renderização fornece os melhores resultados. Mas as APIs de aprovação de renderização podem ser executadas mesmo em drivers pré-existentes (embora, não necessariamente com melhorias de desempenho).
Esses são os cenários em que as passagens de renderização são projetadas para fornecer valor.
Permitir que seu aplicativo evite cargas/repositórios desnecessários de recursos de/para memória principal em uma arquitetura de TBDR (renderização adiada) Tile-Based
Uma das propostas de valor dos passes de renderização é que ele fornece uma localização central para indicar as dependências de dados do aplicativo para um conjunto de operações de renderização. Essas dependências de dados permitem que o driver de exibição inspecione esses dados em tempo de associação/barreira e emita instruções que minimizem cargas/armazenamentos de recursos de/para memória principal.
Permitir que sua arquitetura TBDR retome recursos de forma oportunista no cache no chip em passagens de renderização (mesmo em listas de comandos separadas)
Nota
Especificamente, esse cenário é limitado aos casos em que você está gravando nos mesmos destinos de renderização em várias listas de comandos.
Um padrão de renderização comum é que seu aplicativo seja renderizado para os mesmos destinos de renderização em várias listas de comandos serialmente, mesmo que os comandos de renderização sejam gerados em paralelo. O uso de passes de renderização nesse cenário permite que essas passagens sejam combinadas de tal forma (já que o aplicativo sabe que retomará a renderização na lista de comandos de êxito imediato) que o driver de exibição pode evitar uma liberação para a memória principal nos limites da lista de comandos.
Responsabilidades do aplicativo
Mesmo com o recurso de passes de renderização, nem o runtime do Direct3D 12 nem o driver de exibição assumem a responsabilidade de deduzer oportunidades para reordar/evitar cargas e repositórios. Para aproveitar corretamente o recurso de passes de renderização, seu aplicativo tem essas responsabilidades.
- Identifique corretamente as dependências de dados/ordenação para suas operações.
- Ordene seus envios de forma a minimizar as liberações (portanto, minimize o uso de sinalizadores de _PRESERVE).
- Use corretamente as barreiras de recursos e acompanhe o estado do recurso.
- Evite cópias/desmarcações desnecessárias. Para ajudar a identificá-los, você pode usar os avisos de desempenho automatizados da ferramenta PIX no Windows.
Usando o recurso de passagem de renderização
O que é um de passagem de renderização?
Um passe de renderização é definido por esses elementos.
- Um conjunto de associações de saída que são corrigidas durante a passagem de renderização. Essas associações são para uma ou mais RTVs (exibições de destino de renderização) e/ou para uma exibição de estêncil de profundidade (DSV).
- Uma lista de operações de GPU direcionadas a esse conjunto de associações de saída.
- Metadados que descrevem as dependências de carregamento/armazenamento para todas as associações de saída direcionadas pela passagem de renderização.
Declarar suas associações de saída
No início de uma passagem de renderização, você declara associações aos destinos de renderização e/ou ao buffer de profundidade/estêncil. É opcional associar a destinos de renderização e é opcional associar a um buffer de profundidade/estêncil. Mas você deve associar a pelo menos um dos dois e, no exemplo de código abaixo, associamos a ambos.
Você declara essas associações em uma chamada para ID3D12GraphicsCommandList4::BeginRenderPass.
void render_passes(::ID3D12GraphicsCommandList4 * pIGCL4,
D3D12_CPU_DESCRIPTOR_HANDLE const& rtvCPUDescriptorHandle,
D3D12_CPU_DESCRIPTOR_HANDLE const& dsvCPUDescriptorHandle)
{
const float clearColor4[]{ 0.f, 0.f, 0.f, 0.f };
CD3DX12_CLEAR_VALUE clearValue{ DXGI_FORMAT_R32G32B32_FLOAT, clearColor4 };
D3D12_RENDER_PASS_BEGINNING_ACCESS renderPassBeginningAccessClear{ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, { clearValue } };
D3D12_RENDER_PASS_ENDING_ACCESS renderPassEndingAccessPreserve{ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, {} };
D3D12_RENDER_PASS_RENDER_TARGET_DESC renderPassRenderTargetDesc{ rtvCPUDescriptorHandle, renderPassBeginningAccessClear, renderPassEndingAccessPreserve };
D3D12_RENDER_PASS_BEGINNING_ACCESS renderPassBeginningAccessNoAccess{ D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, {} };
D3D12_RENDER_PASS_ENDING_ACCESS renderPassEndingAccessNoAccess{ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, {} };
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC renderPassDepthStencilDesc{ dsvCPUDescriptorHandle, renderPassBeginningAccessNoAccess, renderPassBeginningAccessNoAccess, renderPassEndingAccessNoAccess, renderPassEndingAccessNoAccess };
pIGCL4->BeginRenderPass(1, &renderPassRenderTargetDesc, &renderPassDepthStencilDesc, D3D12_RENDER_PASS_FLAG_NONE);
// Record command list.
pIGCL4->EndRenderPass();
// Begin/End further render passes and then execute the command list(s).
}
Defina o primeiro campo da estrutura D3D12_RENDER_PASS_RENDER_TARGET_DESC para o identificador do descritor de CPU correspondente a uma ou mais RTVs (exibições de destino de renderização). Da mesma forma, D3D12_RENDER_PASS_DEPTH_STENCIL_DESC contém o identificador do descritor de CPU correspondente a uma DSV (exibição de estêncil de profundidade). Esses identificadores de descritor de CPU são os mesmos que você passaria para ID3D12GraphicsCommandList::OMSetRenderTargets. E, assim como acontece com OMSetRenderTargets, os descritores de CPU são de seus respectivos heaps (descritor de CPU) no momento da chamada para BeginRenderPass.
Os RTVs e DSV não são herdados na passagem de renderização. Em vez disso, eles devem ser definidos. Nem os RTVs e DSV são declarados em BeginRenderPass propagados para a lista de comandos. Em vez disso, eles estão em um estado indefinido após a passagem de renderização.
Renderizar passagens e cargas de trabalho
Você não pode aninhar passagens de renderização e não pode ter uma passagem de renderização entre mais de uma lista de comandos (elas devem começar e terminar durante a gravação em uma única lista de comandos). As otimizações projetadas para habilitar a geração eficiente de passes de renderização de vários threads são discutidas na seção renderizar sinalizadores, abaixo.
Uma gravação que você faz de dentro de um passe de renderização não é válida para você ler até um passe de renderização subsequente. Isso impede alguns tipos de barreiras de dentro da passagem de renderização, por exemplo, a barreira de RENDER_TARGET para SHADER_RESOURCE no destino de renderização associado no momento. Para obter mais informações, consulte a seção Renderizar passagens e barreiras de recursos, abaixo.
A única exceção à restrição de leitura de gravação mencionada envolve as leituras implícitas que ocorrem como parte do teste de profundidade e da combinação de destino de renderização. Portanto, essas APIs não serão permitidas em uma passagem de renderização (o runtime principal removerá a lista de comandos se alguma delas for chamada durante a gravação).
- ID3D12GraphicsCommandList1::AtomicCopyBufferUINT
- ID3D12GraphicsCommandList1::AtomicCopyBufferUINT64
- ID3D12GraphicsCommandList4::BeginRenderPass
- ID3D12GraphicsCommandList::ClearDepthStencilView
- ID3D12GraphicsCommandList::ClearRenderTargetView
- ID3D12GraphicsCommandList::ClearState
- ID3D12GraphicsCommandList::ClearUnorderedAccessViewFloat
- ID3D12GraphicsCommandList::ClearUnorderedAccessViewUint
- ID3D12GraphicsCommandList::CopyBufferRegion
- ID3D12GraphicsCommandList::CopyResource
- ID3D12GraphicsCommandList::CopyTextureRegion
- ID3D12GraphicsCommandList::CopyTiles
- ID3D12GraphicsCommandList::D iscardResource
- ID3D12GraphicsCommandList::D ispatch
- ID3D12GraphicsCommandList::OMSetRenderTargets
- ID3D12GraphicsCommandList::ResolveQueryData
- ID3D12GraphicsCommandList::ResolveSubresource
- ID3D12GraphicsCommandList1::ResolveSubresourceRegion
- ID3D12GraphicsCommandList3::SetProtectedResourceSession
Renderizar passagens e barreiras de recursos
Você não pode ler ou consumir uma gravação que ocorreu na mesma passagem de renderização. Determinadas barreiras não estão em conformidade com essa restrição, por exemplo, de D3D12_RESOURCE_STATE_RENDER_TARGET a *_SHADER_RESOURCE no destino de renderização associado no momento (e a camada de depuração ocorrerá com esse efeito). Porém, essa mesma barreira em um destino de renderização que foi gravado fora o passe de renderização atual é compatível, pois as gravações serão concluídas antes do início da passagem de renderização atual. Você pode se beneficiar de saber sobre determinadas otimizações que um driver de exibição pode fazer nesse sentido. Dada uma carga de trabalho em conformidade, um driver de exibição pode mover as barreiras encontradas em sua passagem de renderização para o início da passagem de renderização. Lá, eles podem ser agrupados (e não interferir em nenhuma operação de dimensionamento/binagem). Essa é uma otimização válida desde que todas as suas gravações tenham sido concluídas antes do início da passagem de renderização atual.
Aqui está um exemplo de otimização de driver mais completo, que pressupõe que você tenha um mecanismo de renderização que tenha um design de associação de recursos no estilo pré-Direct3D 12, fazendo barreiras sob demanda com base em como os recursos são associados. Ao gravar em um UAV (modo de exibição de acesso não ordenado) no final de um quadro (a ser consumido no quadro a seguir), o mecanismo pode deixar o recurso no estado D3D12_RESOURCE_STATE_UNORDERED_ACCESS na conclusão do quadro. No quadro a seguir, quando o mecanismo for associar o recurso como uma SRV (exibição de recurso de sombreador), ele descobrirá que o recurso não está no estado correto e emitirá uma barreira de D3D12_RESOURCE_STATE_UNORDERED_ACCESS para D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE. Se essa barreira ocorrer dentro da passagem de renderização, o driver de exibição será justificado ao supondo que todas as gravações já tenham ocorrido fora dessa passagem de renderização atual e, consequentemente (e aqui está a localização da otimização), o driver de exibição pode mover a barreira até o início da passagem de renderização. Novamente, isso é válido, desde que seu código esteja em conformidade com a restrição de leitura de gravação descrita nesta seção e a última.
Estes são exemplos de barreiras em conformidade.
- D3D12_RESOURCE_STATE_UNORDERED_ACCESSD3D12_RESOURCE_STATE_INDIRECT_ARGUMENT.
- D3D12_RESOURCE_STATE_COPY_DEST para *_SHADER_RESOURCE.
E estes são exemplos de barreiras não conformantes.
- D3D12_RESOURCE_STATE_RENDER_TARGET a qualquer estado de leitura em RTVs/DSVs atualmente associados.
- D3D12_RESOURCE_STATE_DEPTH_WRITE a qualquer estado de leitura em RTVs/DSVs atualmente associados.
- Qualquer barreira de alias.
- Barreiras de UAV (exibição de acesso não ordenada).
Declaração de acesso a recursos
No BeginRenderPass tempo, além de declarar todos os recursos que estão servindo como RTVs e/ou DSV dentro dessa passagem, você também deve especificar o início e o término acesso características. Como você pode ver no exemplo de código na seção Declare suas associações de saída acima, faça isso com as estruturas D3D12_RENDER_PASS_RENDER_TARGET_DESC e D3D12_RENDER_PASS_DEPTH_STENCIL_DESC.
Para obter mais detalhes, consulte as estruturas de D3D12_RENDER_PASS_BEGINNING_ACCESS e D3D12_RENDER_PASS_ENDING_ACCESS e as enumerações D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE e D3D12_RENDER_PASS_ENDING_ACCESS_TYPE.
Renderizar sinalizadores de passagem
O último parâmetro passado para BeginRenderPass é um sinalizador de passagem de renderização (um valor da enumeração D3D12_RENDER_PASS_FLAGS).
enum D3D12_RENDER_PASS_FLAGS
{
D3D12_RENDER_PASS_FLAG_NONE = 0,
D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES = 0x1,
D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS = 0x2,
D3D12_RENDER_PASS_FLAG_RESUMING_PASS = 0x4
};
Gravações do UAV em um passe de renderização
Gravações de UAV (exibição de acesso não ordenada) são permitidas em um passe de renderização, mas você deve indicar especificamente que emitirá gravações UAV dentro da passagem de renderização especificando D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES, de modo que o driver de exibição possa recusar o bloco, se necessário.
Os acessos de UAV devem seguir a restrição de leitura de gravação descrita acima (as gravações em um passe de renderização não são válidas para leitura até uma passagem de renderização subsequente). As barreiras UAV não são permitidas em uma passagem de renderização.
As associações UAV (por meio de tabelas raiz ou descritores raiz) são herdadas em passes de renderização e propagadas para fora dos passes de renderização.
Suspending-passes, and resuming-passes
Você pode indicar uma passagem de renderização inteira como sendo uma passagem de suspensão e/ou uma passagem de retomada. Um par suspending-followed-by-a-resuming deve ter exibições/sinalizadores de acesso idênticos entre as passagens e pode não ter operações de GPU intervenientes (por exemplo, sorteios, expedições, descartes, limpezas, cópias, mapeamentos de bloco de atualização, write-buffer-immediates, consultas, resoluções de consulta) entre a suspensão da passagem de renderização e o passe de renderização de retomada.
O caso de uso pretendido é a renderização de vários threads, em que, digamos, quatro listas de comandos (cada uma com suas próprias passagens de renderização) podem ter como destino os mesmos destinos de renderização. Quando os passes de renderização são suspensos/retomados entre listas de comandos, as listas de comandos devem ser executadas na mesma chamada para ID3D12CommandQueue::ExecuteCommandLists.
Uma passagem de renderização pode ser retomada e suspensa. No exemplo de vários threads que acabou de ser dado, as listas de comandos 2 e 3 seriam retomadas de 1 e 2, respectivamente. E, ao mesmo tempo, 2 e 3 estariam suspendendo para 3 e 4, respectivamente.
Consulta para suporte a recursos de passagem de renderização
Você pode chamar ID3D12Device::CheckFeatureSupport para consultar até que ponto um driver de dispositivo e/ou o hardware dão suporte eficiente à renderização.
D3D12_RENDER_PASS_TIER get_render_passes_tier(::ID3D12Device * pIDevice)
{
D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureSupport{};
winrt::check_hresult(
pIDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &featureSupport, sizeof(featureSupport))
);
return featureSupport.RenderPassesTier;
}
...
D3D12_RENDER_PASS_TIER renderPassesTier{ get_render_passes_tier(pIDevice) };
Devido à lógica de mapeamento do runtime, a renderização passa sempre a função. Mas, dependendo do suporte a recursos, eles nem sempre fornecerão um benefício. Você pode usar um código semelhante ao exemplo de código acima para determinar se/quando vale a pena emitir comandos conforme a renderização passa e quando definitivamente não é um benefício (ou seja, quando o runtime está apenas mapeando para a superfície da API existente). Executar essa verificação é particularmente importante se você estiver usando D3D11On12).
Para obter uma descrição das três camadas de suporte, consulte a enumeração D3D12_RENDER_PASS_TIER.