Programação assíncrona (DirectX e C++)

Applies to Windows and Windows Phone

Este tópico abrange vários pontos que devem ser considerados quando você estiver usando a programação assíncrona e fazendo thread com DirectX. Você pode ler sobre padrões gerais de programação assíncrona (não é específico para DirectX) em Programação assíncrona com C++.

(Para saber mais sobre a programação assíncrona com o JavaScript ou uma linguagem .NET, veja Programação assíncrona em JavaScript e Programação assíncrona em .NET, respectivamente.)

Programação assíncrona e DirectX

Se você estiver apenas aprendendo DirectX ou mesmo que você já esteja familiarizado com ele, considere colocar todo o pipeline de processamento de elementos gráficos em um único thread. Em qualquer cena de um jogo, há recursos comuns como bitmaps, sombreadores e outros ativos que exigem acesso exclusivo. Esses mesmos recursos exigem que você sincronize qualquer acesso a esses recursos em todos os threads paralelos. A renderização é um processo difícil para colocar em paralelo vários threads.

Entretanto, se o jogo for suficientemente complexo ou se você estiver tentando obter um maior desempenho, poderá usar a programação assíncrona para colocar em paralelo alguns dos componentes que não sejam específicos para o pipeline de renderização. O hardware moderno contém vários cores e CPUs com hyperthread e o aplicativo deve aproveitar isso! Você pode assegurar isso usando programação assíncrona para alguns dos componentes do jogo que não precisam de acesso direto ao contexto de dispositivo Direct3D, como:

  • E/S de arquivo
  • física
  • Inteligência Artificial
  • recursos de rede
  • áudio
  • controles
  • Componentes da interface do usuário baseados em XAML

O aplicativo pode manipulá-los em vários threads simultâneos. A E/S de arquivo, especialmente o carregamento de ativo, se beneficia muito do carregamento assíncrono, porque o jogo ou o aplicativo pode estar em um estado interativo enquanto vários (ou várias centenas) megabytes de ativos estão sendo carregados ou transmitidos. A maneira mais fácil de criar e gerenciar esses threads é usando a Biblioteca de Padrões Paralelos e o padrão task, conforme contido no namespace concurrency definido em PPLTasks.h. O uso da Biblioteca de Padrões Paralelos traz a vantagem direta de vários core e CPUs com hyperthread, e pode aprimorar tudo desde os tempos de carga percebidos até os problemas e atrasos ocasionados por cálculos da CPU ou processamento de rede intensivos.

Leia Programação assíncrona com C++ para saber mais sobre a programação assíncrona que usa a Biblioteca de Padrões Paralelos.

O seguinte exemplo de código demonstra o uso do carregamento assíncrono para texturas DDS:

Observação  Em um aplicativo da Windows Store, a interface do usuário é executada inteiramente em um STA (single-threaded apartment). Se você estiver criando uma interface de usuário para o jogo em DirectX que usa interoperabilidade XAML, só será possível acessar os controles usando STA.

Multithreading com dispositivos Direct3D

O multithreading para contexto de dispositivo está disponível somente em dispositivos de elementos de gráficos que permitem um nível de recurso Direct3D de 11_0 ou superior. Entretanto, você pode desejar maximizar o uso da GPU poderosa em muitas plataformas, como plataformas dedicadas de jogos. No caso mais simples, você pode desejar separar a renderização de uma sobreposição de HUD (heads-up display, painel transparente) da renderização e projeção da cena 3D e fazer com que os dois componentes usem pipelines paralelos separados. Os dois threads devem usar o mesmo ID3D11DeviceContext para criar e gerenciar os objetos do recurso (as texturas, as malhas, os sombreadores e outros ativos), mesmo, o que estiver com thread único e que exigir implementação de algum tipo de mecanismo de sincronização (como seções críticas) para acessá-lo com segurança. E enquanto você cria listas de comandos separadas para o contexto do dispositivo em threads diferentes (para renderização adiada), não é possível executar aquelas listas de comandos simultaneamente na mesma instância ID3D11DeviceContext.

Agora, o aplicativo também pode usar ID3D11Device, que é seguro para multithreading, para criar objetos de recurso. Então, por que não usar sempre o ID3D11Device em vez do ID3D11DeviceContext? Bem, atualmente, o suporte para driver para multithreading pode não estar disponível para algumas interfaces gráficas. Você pode consultar o dispositivo e descobrir se ele realmente permite multithreading, mas se você estiver tentando alcançar um público mais amplo, poderá adotar o ID3D11DeviceContext de thread único para o gerenciamento do objeto do recurso. Dito isso, quando o driver de dispositivo gráfico não permite multithreading ou listas de comandos, o Direct3D 11 tenta controlar o acesso sincronizado para o contexto do dispositivo internamente; e quando as listas de comandos não são permitidas, ele fornece uma implementação de software. Como resultado, você pode escrever o código com multithread que será executado em plataformas com interfaces gráficas que não possuem suporte de driver para acesso de contexto de dispositivo com multithread.

Se o aplicativo aceitar threads separados para processar listas de comandos e para exibir quadros, provavelmente você desejará manter a GPU ativa, processando as listas de comandos enquanto exibe os quadros em tempo hábil sem gagueira ou atraso perceptível. Nesse caso, você poderia usar um ID3D11DeviceContext separado para cada thread e compartilhar os recursos (como texturas) criando-os com o sinalizador D3D11_RESOURCE_MISC_SHARED. Nesse cenário, o ID3D11DeviceContext::Flush deve ser chamado no thread de processamento para concluir a execução da lista de comandos antes de exibir os resultados do processamento do objeto do recurso no thread de exibição.

Renderização adiada

A renderização adiada registra os comandos gráficos em uma lista de comandos, dessa forma, eles podem ser reproduzidos em algum outro momento e é projetada para permitir a renderização em um único thread enquanto registra comandos para renderizar em threads adicionais. Depois que esses comandos forem concluídos, eles poderão ser executados no thread que gera o objeto de exibição final (buffer de quadros, textura ou outra saída de elementos gráficos).

Crie um contexto adiado usando ID3D11Device::CreateDeferredContext (em vez de D3D11CreateDevice ou D3D11CreateDeviceAndSwapChain, que cria um contexto imediato). Para saber mais, veja Renderização imediata e adiada.

Tópicos relacionados

Programação assíncrona com C++
Desenvolvendo aplicativos (C++ e DirectX)
Introdução ao multithreading no Direct3D 11
Escrevendo código para aplicativos da Windows Store (DirectX e C++)

 

 

Mostrar:
© 2014 Microsoft