Qual dessas chamadas do DirectX11 realmente envia dados para a GPU?

7

Estou tentando aprender programação gráfica e DirectX11.

Estou tentando aprender como minimizar a transferência de CPU-GPU e a programação gráfica em geral.
Tenho uma pergunta que não consegui responder a partir de recursos online:

Qual dos métodos D3D realmente envia os dados para a GPU (e, equivalentemente, para uma malha estática, TODOS os dados de vértice são transmitidos à GPU a cada quadro, ou apenas uma vez)?

Código a seguir:
(simplificado para stackexchange)

Na minha classe "mesh", tenho um buffer de vértice:

ID3D11Buffer *m_pVBuffer;

No construtor da minha malha, defino alguns vértices para o buffer de vértice:

D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(m_pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
memcpy(ms.pData, &vertices[0], sizeof(VERTEX) * vertices.size());
devcon->Unmap(m_pVBuffer, NULL);

Então, no método "render" da minha malha, faço o seguinte:

UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &m_pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(m_pIBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->DrawIndexed(m_num_indices, 0, 0);

Para repetir: Os dados são enviados para a GPU quando mapeio, memcpy e Unmap o buffer de vértice, ou são carregados todos os quadros quando chamo IASetVertexBuffers?

x10
fonte

Respostas:

7

Essa é uma pergunta complicada, porque você não tem controle completo sobre se um buffer de vértice é armazenado na VRAM ou na RAM principal. O driver toma essa decisão com base nos sinalizadores de uso e acesso à CPU especificados quando você cria o buffer de vértice.

De um modo geral, os buffers com uso padrão e imutável serão armazenados na VRAM; aqueles com uso temporário serão armazenados na RAM principal; e aqueles com uso dinâmico podem estar em qualquer lugar. No entanto, se houver VRAM insuficiente, o driver armazenará recursos na RAM principal como substituto.

Se um buffer termina na VRAM, os dados passam pelo barramento do sistema (que conecta a CPU e a GPU) sempre que a CPU atualiza o buffer (ou seja, quando você faz um par Map / Unmap). Se estiver na RAM principal, a GPU lerá os dados no barramento do sistema toda vez que você usar esse buffer para renderização.

Portanto, normalmente, para malhas estáticas, você usaria o uso imutável e o buffer seria armazenado na VRAM, para que não haja transferência de barramento do sistema adicional após a configuração inicial. Para um buffer de vértice dinâmico (para partículas ou similar), você usaria o uso dinâmico e os dados atravessariam o barramento uma vez a cada quadro - se estiver na VRAM, o barramento será usado para a CPU gravar nele e se na RAM principal, o barramento será usado pela GPU para lê-lo.

Nathan Reed
fonte
Os testes que corri confirmam esta resposta. Quando eu renderizo muitos objetos, há uma desaceleração inicial nos primeiros segundos, mas a taxa de quadros aumenta. Dado que eu faço a mesma coisa em todos os quadros, isso deve ser porque pelo menos uma parte dos buffers é "armazenada em cache" na VRAM. Portanto, a resposta é "Ele será carregado apenas uma vez. Provavelmente. Você não deve contar com isso".
x10
0

A resposta dependerá do que qualquer geração específica de driver de hardware altamente otimizado se sentir fazendo, ou seja, que não há uma resposta geral para você.

Adicione a essa complicação o fato de os drivers renderizarem os quadros 1-N atrás do que você está dizendo para eles renderizarem porque as placas 3D são altamente serializadas e paralelas e armazenadas em cache e funcionam de forma assíncrona para realizar as tarefas.

Se você está apenas aprendendo, as informações importantes a serem conhecidas são os pontos de sequência para preparar uma renderização: descreva os dados, copie-os, informe ao motorista quais dados usar e, em seguida, dispare a renderização. E não é o que acontece quando, na verdade, é uma toca de coelho muito profunda.

Patrick Hughes
fonte
0

O meu entendimento, principalmente com base na leitura deste é que o motorista geralmente não enviará quaisquer recursos em toda a memória de vídeo, até que o recurso é usado em uma chamada de desenho.

Isso significaria que o construtor provavelmente não tocará no hardware da GPU e o método de renderização. No entanto, mesmo a chamada DrawIndexed () provavelmente não chegará ao hardware imediatamente, porque é mais eficiente na CPU armazenar em buffer grandes listas de comandos da GPU.

O driver também pode descarregar dados da memória da GPU quando acabar (supondo que haja uma cópia deles na RAM principal). Em casos extremos, isso pode acontecer mais de uma vez por quadro.

É claro que tudo isso está oculto no programador pelo driver, então você não pode confiar nisso - os drivers mudam o tempo todo.

Adão
fonte
É altamente possível que ele nem atenda a uma chamada de empate - a chamada de empate é direcionada a um buffer de comando gerenciado pelo driver, e isso é liberado no próprio tempo agradável do motorista, que pode ser uma quantidade arbitrária de tempo depois.
Maximus Minimus