Tempo de vida e sincronização de recursos
Assim como no Direct3D 12 (para evitar comportamento indefinido), seu aplicativo DirectML deve gerenciar corretamente a vida útil do objeto e a sincronização entre a CPU e a GPU. O DirectML segue um modelo de vida útil de recurso 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 filho de dispositivo contém uma forte referência ao seu dispositivo pai.
- As dependências de tempo de vida entre objetos de GPU ou dependências que abrangem a CPU e a GPU não são gerenciadas automaticamente. É responsabilidade do aplicativo garantir que os recursos da GPU fiquem ativos pelo menos até que todo o trabalho que usa esse recurso tenha concluído a execução na GPU.
Dispositivos DirectML
O dispositivo DirectML é um objeto de fábrica sem monitoração de estado thread-safe. Cada filho de dispositivo (consulte IDMLDeviceChild) contém uma forte referência ao seu dispositivo DirectML pai (consulteIDMLDevice). Isso significa que você sempre pode recuperar a interface do dispositivo pai de qualquer interface filho do dispositivo.
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 corresponder filhos de dispositivos que pertencem a dispositivos diferentes. Por exemplo, IDMLBindingTable e IDMLCompiledOperator são dois tipos de filhos de dispositivos (ambas as interfaces derivam direta ou indiretamente de IDMLDeviceChild). E você não poderá usar uma tabela de vinculação (IDMLBindingTable) para vincular a um operador (IDMLCompiledOperator) se o operador e a tabela de associaçã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 Tratar os erros e a remoção de dispositivo no DirectML.
Requisitos de vida útil 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 ativos enquanto eles estão em uso pela GPU. Em vez disso, essas são responsabilidades do seu aplicativo.
Ao executar uma lista de comandos que contém expedições 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 dá suporte à tabela de vinculação que está sendo usada para vincular o operador.
- Os objetos ID3D12Resource vinculados como entradas/saídas do operador.
- Os objetos ID3D12Resource vinculados como recursos persistentes e temporários, se aplicável.
- O ID3D12CommandAllocator que dá suporte à própria lista de comandos.
Nem todas as interfaces DirectML representam recursos de GPU. Por exemplo, uma tabela de vinculação não precisa ser mantida ativa até que todas as expedições que a usam tenham concluído a execução na GPU. Isso ocorre porque a tabela de vinculação em si não tem nenhum recurso de GPU. Em vez disso, o heap do descritor tem. 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 comando deve ser mantido ativo até que todas as execuções que o utilizam tenham sido concluídas na GPU, já que ele tem memória GPU. Porém, uma lista de comandos não tem memória GPU; portanto, pode ser redefinida ou liberada assim que for enviada para execução.
No DirectML, os operadores compilados (IDMLCompiledOperator) e os inicializadores de operador (IDMLOperatorInitializer) têm recursos de GPU diretamente; portanto, devem ser mantidos ativos até que todas as expedições que os usam tenham concluído a execução na GPU. Além disso, qualquer recurso do Direct3D 12 que está sendo usado (alocadores de comando, heaps de descritores, buffers, como exemplos) deve ser mantido ativo pelo seu aplicativo.
Se você liberar prematuramente um objeto enquanto ele ainda estiver em uso pela GPU, o resultado será 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 não envia nenhum trabalho para execução na GPU. Em vez disso, o método IDMLCommandRecorder::RecordDispatch registra a expedição desse trabalho em uma lista de comandos para execução posterior. Seu aplicativo deve fechar e enviar sua lista de comandos para execução chamando ID3D12CommandQueue::ExecuteCommandLists, como acontece com 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 isolamentos, nem executa qualquer forma de sincronização de CPU/GPU em seu nome. É responsabilidade do aplicativo usar itens primitivos do Direct3D 12 apropriados para aguardar que o trabalho enviado conclua a execução na GPU, se necessário. Para obter mais informações, consulte ID3D12Fence e ID3D12CommandQueue::Signal.