Partilhar via


Tempo de vida e sincronização do recurso

Assim como no Direct3D 12, seu aplicativo DirectML deve (para evitar comportamentos indefinidos) gerenciar corretamente o tempo de vida do objeto e a sincronização entre a CPU e a GPU. O DirectML segue um modelo de tempo de vida de recursos idêntico ao do Direct3D 12.

  • As dependências de tempo de vida entre dois objetos de CPU são mantidas pelo DirectML usando contagens de referência fortes. Seu aplicativo não precisa gerenciar manualmente as dependências do tempo de vida da CPU. Por exemplo, cada dispositivo filho mantém uma referência forte ao seu dispositivo pai.
  • As dependências vitalícias entre objetos de GPU — ou dependências que abrangem CPU e GPU — não são gerenciadas automaticamente. É responsabilidade do seu aplicativo garantir que os recursos da GPU permaneçam pelo menos até que todo o trabalho usando esse recurso tenha concluído a execução na GPU.

Dispositivos DirectML

O dispositivo DirectML é um objeto de fábrica sem estado e seguro para execução simultânea. Cada filho do dispositivo (consulte IDMLDeviceChild) mantém uma ligação forte ao seu dispositivo DirectML pai (consulte IDMLDevice). Isso significa que você sempre pode recuperar a interface do dispositivo pai de qualquer interface de dispositivo filha.

Um dispositivo DirectML, por sua vez, contém uma forte referência ao dispositivo Direct3D 12 que foi usado para criá-lo (consulte ID3D12Device e interfaces derivadas).

Como o dispositivo DirectML é sem estado, ele é implicitamente thread-safe. Você pode chamar métodos no dispositivo DirectML de vários threads simultaneamente sem a necessidade de sincronização externa.

No entanto, ao contrário do dispositivo Direct3D 12, o dispositivo DirectML não é um objeto singleton. Você é livre para criar quantos dispositivos DirectML desejar. No entanto, você não pode misturar e combinar filhos de dispositivos que pertencem a dispositivos diferentes. Por exemplo, IDMLBindingTable e IDMLCompiledOperator são dois tipos de filhos de dispositivo (ambas as interfaces derivam direta ou indiretamente de IDMLDeviceChild). E você não pode usar uma tabela de vinculação (IDMLBindingTable) para vincular um operador (IDMLCompiledOperator) se o operador e a tabela de vinculação pertencerem a instâncias de dispositivo DirectML diferentes.

Como o dispositivo DirectML não é um singleton, a remoção do dispositivo ocorre por dispositivo, em vez de ser um evento de todo o processo, como é para um dispositivo Direct3D 12. Para obter mais informações, consulte Tratamento de erros e remoção de dispositivos no DirectML.

Requisitos de tempo de vida dos recursos da GPU

Como o Direct3D 12, o DirectML não sincroniza automaticamente entre a CPU e a GPU; nem mantém automaticamente os recursos vivos enquanto estão em uso pela GPU. Em vez disso, estas são responsabilidades da sua aplicação.

Ao executar uma lista de comandos que contém despachos DirectML, seu aplicativo deve garantir que os recursos da GPU sejam mantidos ativos até que todo o trabalho usando esses recursos tenha concluído a execução na GPU.

No caso de IDMLCommandRecorder::RecordDispatch para um operador DirectML, isso inclui os seguintes objetos.

  • O IDMLCompiledOperator sendo executado (ou IDMLOperatorInitializer em vez disso, se estiver executando a inicialização do operador).
  • O IDMLCompiledOperator que suporta a tabela de associação utilizada para ligar o operador.
  • Os objetos ID3D12Resource vinculados como as entradas/saídas do operador.
  • Os objetos ID3D12Resource vinculados como recursos persistentes e temporários, se aplicável.
  • O ID3D12CommandAllocator que suporta a própria lista de comandos.

Nem todas as interfaces DirectML representam recursos da GPU. Por exemplo, uma tabela de vinculação não precisa ser mantida ativa até que todos os despachos que a usam tenham concluído a execução na GPU. Isso ocorre porque a tabela de vinculação em si não possui nenhum recurso de GPU. Em vez disso, o descritor heap faz. Portanto, o heap do descritor subjacente é o objeto que deve ser mantido ativo até que a execução seja concluída, e não a tabela de vinculação em si.

Um conceito semelhante existe no Direct3D 12. Um alocador de comandos deve ser mantido ativo até que todas as execuções que o utilizam tenham sido concluídas na GPU; uma vez que possui memória GPU. Mas, uma lista de comandos não possui memória GPU, portanto, ela pode ser redefinida ou liberada assim que for enviada para execução.

No DirectML, os operadores compilados (IDMLCompiledOperator) e os inicializadores de operador (IDMLOperatorInitializer) possuem recursos de GPU diretamente, portanto, eles devem ser mantidos ativos até que todos os despachos que os usam tenham concluído a execução na GPU. Além disso, qualquer recurso do Direct3D 12 que esteja a ser utilizado (alocadores de comando, heaps de descritores, buffers, como exemplos) também deve ser mantido ativo pela sua aplicação.

Se você liberar prematuramente um objeto enquanto ele ainda está em uso pela GPU, o resultado é um comportamento indefinido, que tem o potencial de causar a remoção do dispositivo ou outros erros.

Sincronização de CPU e GPU

O DirectML em si não envia nenhum trabalho para execução na GPU. Em vez disso, o método IDMLCommandRecorder::RecordDispatchregistra o envio desse trabalho em uma lista de comandos para execução posterior. Seu aplicativo deve então fechar e enviar sua lista de comandos para execução chamando ID3D12CommandQueue::ExecuteCommandLists, como em qualquer lista de comandos do Direct3D 12.

Como o DirectML não envia nenhum trabalho para execução na GPU, ele também não cria cercas, nem executa qualquer forma de sincronização CPU/GPU em seu nome. É responsabilidade do seu aplicativo usar as primitivas Direct3D 12 apropriadas para aguardar o trabalho enviado para concluir a execução na GPU, se necessário. Para obter mais informações, consulte ID3D12Fence e ID3D12CommandQueue::Signal.

Ver também