Compartilhar via


Principais problemas para títulos do Windows

O grupo Relações do Desenvolvedor de Tecnologias de Jogos e Gráficos do Microsoft Windows executa análises de desempenho para muitos jogos do Windows a cada ano. Durante essas sessões, obtemos experiência prática para nos unirmos aos comentários e consultas do desenvolvedor que recebemos diariamente. Ocasionalmente, ajudamos a rastrear uma falha misteriosa ou outro problema em um título, o que nos dá mais informações sobre os problemas que os desenvolvedores estão encontrando.

Este artigo destaca muitos dos problemas comuns que vimos em jogos de pc de geração atual.

Desempenho do CPU-Limited

A grande maioria dos jogos é limitada pelo desempenho da CPU em sistemas com GPUs (unidades de processamento gráfico) de alto desempenho. Às vezes, isso ocorre devido ao mau uso do envio em lote para envios de desenho, mas, mais normalmente, isso ocorre devido a outros sistemas de jogos que consomem uma grande parte dos ciclos de CPU disponíveis. Nos poucos casos em que vimos a GPU como a limitação, a causa são taxas de preenchimento muito altas ou demanda de sombreador de pixel, em configurações de alta resolução ou baixo desempenho de sombreador de vértice por um vídeo cartão.

Como a maioria dos títulos é limitada pela CPU, as maiores vitórias de desempenho vêm da otimização de sistemas de jogos com uso intensivo de CPU. Normalmente, os sistemas de IA ou física e a lógica de detecção de colisão associada são os principais consumidores de ciclos de CPU em aplicativos Microsoft Direct3D bem comportados. Qualquer trabalho para melhorar esses sistemas pode melhorar o desempenho geral do jogo.

Gerenciamento de Lote insatisfatório

Alcançar um bom paralelismo com a GPU requer que os lotes de desenho contenham geometria suficiente — e os sombreadores têm a complexidade certa — para manter o vídeo cartão ocupado, sem usar tantos lotes que o buffer de comando está inundado. No hardware de geração atual, recomendamos aproximadamente 300 ou menos envios de lote de desenho por quadro (menos em CPUs de baixo desempenho) para impedir que o processamento do buffer de comando do driver se torne um gargalo de desempenho. Algumas outras chamadas de estado de API e combinações de driver podem resultar em processamento de CPU caro (compilação de driver de sombreadores, por exemplo), portanto, é altamente recomendável a análise de desempenho de rotina.

Cópia excessiva de memória

Durante o desenvolvimento da maioria dos títulos de computador, os desenvolvedores usam estruturas de dados e cadeias de caracteres convenientes para gerenciamento de conteúdo. O trabalho de CPU necessário para comparação de cadeias de caracteres, cópia e outras manipulações geralmente tem uma sobrecarga mensurável, especialmente ao levar em conta as ocorrências de desempenho associadas ao subsistema de cache e memória. Planos devem ser feitos ao desenvolver esses sistemas para remover ou minimizar a dependência do processamento de cadeias de caracteres depois que o produto entrar nas fases primárias de teste e lançamento.

Uso excessivo de envio de desenho dinâmico

O hardware de vídeo moderno tem um bom desempenho ao lidar com dados estáticos. Adaptadores high-end geralmente têm uma quantidade muito grande de memória de vídeo, mas essa memória não pode ser efetivamente utilizada por dados dinâmicos.

Embora padrões de uso razoavelmente eficientes de buffers de vértice dinâmicos/buffers de índice possam ser implementados para conteúdo dinâmico, muitos títulos superutilizam essa linguagem para o que de outra forma é conteúdo estático. Geralmente, vemos isso com árvores BSP (particionamento de espaço binário) e sistemas baseados em portal que armazenam geometria em uma estrutura de dados que não é mapeada para o hardware e deve ser processada em buffers para cada quadro. Colocar o máximo de conteúdo possível em recursos estáticos pode reduzir consideravelmente a sobrecarga de largura de banda da transferência de dados para a cartão de vídeo, fazer melhor uso da VRAM integrada e reduzir a sobrecarga de CPU/cache envolvida no processamento desse conteúdo.

Alta sobrecarga no processamento de arquivos

Os jogos de computador ganharam reputação por tempos de carregamento longos, especialmente quando comparados com títulos de console com requisitos estritos de tempo de carregamento. Nossa análise da maneira como muitos títulos usam o subsistema de arquivos revela alguns problemas comuns.

A sobrecarga de abrir um arquivo geralmente é muito maior do que os desenvolvedores esperam. Com scanners de vírus sob demanda em uso generalizado e a funcionalidade adicional do NTFS, abrir um arquivo é uma operação bastante cara. Abrir muitos arquivos de uma só vez ou abrir e fechar o mesmo arquivo repetidamente é, portanto, um método ruim de lidar com o gerenciamento de arquivos. Alguns jogos tentaram reduzir esse custo de desempenho testando a existência de um arquivo antes de abri-lo. A realidade é que testar a existência de um arquivo no NTFS requer a abertura do arquivo, portanto, o teste antes de abrir resulta no pagamento do custo duas vezes.

Jogos que permitem modificações de complemento, ou mods, ou que ainda incluem scaffolding de desenvolvimento para marcar para substituir arquivos de dados, podem ter atrasos significativos no carregamento do jogo devido à verificação desses arquivos, mesmo quando esses arquivos não estão presentes. Recomendamos que os jogos só marcar para esses arquivos quando executados com um comutador de linha de comando especial ou outro indicador de modo, para que apenas os usuários que usam essa funcionalidade realmente paguem o custo de desempenho dessas verificações (geralmente extensas).

O desempenho adicional pode ser obtido do sistema de arquivos pelo seguinte:

  • Uso apropriado das dicas do sistema de arquivos FILE_FLAG_RANDOM_ACCESS e FILE_FLAG_SEQUENTIAL_SCAN
  • Dimensionamento de buffers para evitar uma grande quantidade de chamadas para as APIs de leitura/gravação do sistema operacional
  • Acessando arquivos de forma assíncrona
  • Carregando threads em segundo plano

Também é altamente recomendável converter dados offline (no momento da compilação ou da instalação) em vez de depender da conversão quando o jogo for executado pela primeira vez, pois isso impõe um imposto de desempenho significativo para cada usuário.

Instalação lenta e frustrante

Outro problema comum que vimos são tempos de instalação muito longos necessários para muitos jogos de computador modernos. Os instaladores solicitam ao usuário muitas vezes, às vezes simplesmente para informar ao usuário, por exemplo, "Você não precisa do DirectX instalado". Em geral, esses instaladores ofensivos exigem que o usuário selecione Avançar ou OK muitas vezes antes que a instalação do jogo realmente comece. Depois de começar, vimos alguns títulos levarem uma hora ou mais antes que o usuário tenha a oportunidade de jogar o jogo. Sentimos fortemente que a primeira hora de experiência de jogo não deve ser a instalação.

Recomendamos várias abordagens para lidar com a instalação. Primeiro, mantenha os prompts simples e no mínimo. Em segundo lugar, arquitete seus dados de jogo de modo que alguns ou todos os arquivos de dados possam ser usados diretamente do disco de distribuição sempre que possível — as unidades de DVD modernas têm uma largura de banda muito alta. Em terceiro lugar, considere implementar a instalação sob demanda em seus títulos para reduzir ou eliminar o processo de instalação e permitir que os usuários entrem no jogo o mais rápido possível. (Para obter mais informações sobre como instalar sob demanda, consulte Install-on-Demand for Games.)

Para obter mais recomendações sobre a instalação de jogos, consulte Simplificando a instalação de jogos.

Falta de consideração da memória física

Devido à ampla variabilidade do hardware do computador no mercado, os títulos normalmente usam testes de configuração ad hoc para selecionar as configurações padrão para o nível de detalhes gráficos. Alguns dos títulos que vimos estão usando o tamanho da memória de vídeo nesses testes, mas não correlacionando isso com o tamanho da memória física. Para lidar com situações de dispositivo perdido, a maior parte da memória de vídeo (VRAM local no cartão e a abertura de memória AGP não local) deve ser apoiada pela memória física, seja por meio do uso de recursos gerenciados ou estruturas de dados personalizadas. Algumas placas de vídeo high-end têm tamanhos de VRAM que rivalizam com o tamanho das memórias de CPU de baixo nível. Em situações em que o sistema tem memória física limitada em comparação com a cartão de vídeo, a maior parte dessa VRAM não pode ser utilizada efetivamente e as configurações de detalhes inferiores devem ser definidas.

Over-Reliance na conversão de taxa de amostra de áudio Real-Time

Outra fonte comum de gravação do ciclo da CPU que vimos ocorre quando o sistema de áudio é necessário para converter a taxa de reprodução durante a combinação no buffer de hardware. Com drivers WDM (Modelo de Driver do Windows), o formato de buffer de hardware não está sob controle direto do aplicativo, pois é um recurso no nível do kernel; Em vez disso, o formato é selecionado com base no formato de alta qualidade de todas as fontes e nas funcionalidades do hardware. Por padrão, o Windows XP usa uma conversão de taxa de exemplo de alta qualidade para esse processo e, se a maioria dos exemplos de áudio exigir uma conversão de taxa, uma parte significativa dos ciclos de CPU será consumida.

É recomendável criar todos os buffers directSound com a mesma taxa de amostragem. Se você usar as funções waveOut do Microsoft Win32, também deverá usar uma taxa de amostragem consistente com elas. Com drivers WDM, todos os buffers serão misturados pelo kernel e, se você usar uma taxa de amostragem mais alta em alguns deles, as taxas de amostragem de todo o restante serão convertidas para corresponder. Observe que isso implica usar a mesma taxa de reprodução para todos os seus exemplos de áudio, incluindo quaisquer buffers de descompactação de áudio de streaming. Definir a taxa de buffer primária não tem efeito, a menos que você esteja direcionando o Windows 98 ou o Windows Millennium Edition.

Observação

No Windows Vista e versões posteriores do sistema operacional, DirectSound e waveOut usam a WASAPI (API de Sessão de Áudio) do Windows para todas as saídas de áudio.

 

Fragmentação da memória virtual

Vimos uma série de problemas recentes relacionados ao limite de 32 bits no espaço de memória do processo. Embora 2 GB de espaço de endereço virtual para processos de modo de usuário tenha sido mais do que adequado historicamente, o aumento do uso de arquivos grandes mapeados em memória, alocadores de memória personalizados e aumento do tamanho da VRAM (que deve ser mapeado para o espaço do processo) começou a causar situações em que as alocações de espaço de memória virtual estão falhando. Algumas DLLs que não são da Microsoft estão usando locais de início fixo no meio do espaço de endereço virtual, o que está causando fragmentação que resulta em alocações com falha.

Esses problemas geralmente aparecem quando o jogo usa um esquema de alocação de memória personalizado que tenta alocar uma grande parte contínua do espaço de memória virtual. Nossa recomendação é escrever alocadores de modo que eles solicitem partes mais razoavelmente dimensionadas do espaço de endereço virtual, conforme necessário. Por exemplo, solicitar 64 ou 256 MB por vez, mas não 1 GB. No entanto, deve-se tomar cuidado para não causar mais fragmentação. O advento de sistemas operacionais e hardware de 64 bits ajudará muito esses problemas no futuro, mas é necessário ter cuidado com os sistemas de 32 bits de geração atual.

Manipulação da Word de controle de Floating-Point

Como um auxílio de depuração, alguns desenvolvedores têm habilitado exceções na FPU (unidade de ponto flutuante) por meio de manipulações da palavra de controle de ponto flutuante. Fazer isso é altamente problemático e provavelmente causará falha no processo. Assim como a convenção de chamada exige que o registro ebx seja preservado, a maioria do sistema pressupõe que a FPU está em um estado padrão, fornecerá resultados razoáveis e não gerará exceções. Drivers e outros componentes do sistema geralmente computam resultados com base na suposição de que os valores de erro padrão aparecerão nos registros para condições incorretas, mas se as exceções estiverem habilitadas, eles ficarão sem tratamento e resultarão em falhas.

O Direct3D definirá a unidade de ponto flutuante como de precisão única, arredondada para mais próxima como parte da inicialização do thread de chamada, a menos que o sinalizador de D3DCREATE_FPU_PRESERVE seja usado; nesse caso, a palavra de controle de ponto flutuante não é intocada. Como a palavra de controle é uma configuração por thread, garantir que todos os threads de aplicativo estejam definidos como modo de precisão única pode otimizar o desempenho. Lembre-se de que chamar _control87 não é válido para codificação nativa x64, que usa SSE exclusivamente e é extremamente caro na arquitetura baseada em PowerPC da CPU do Xbox 360.

Observação

Se você modificar a palavra de controle, use _controlfp_s e lembre-se de que, para plataformas x64, não é possível alterar a precisão de ponto flutuante por meio da palavra de controle .

 

Em todas as bibliotecas em que precisamos ter regras de arredondamento diferentes ou outro comportamento, como lidar com sombreadores de vértice de software ou compilação, salvamos e restauramos a palavra de controle. Se um jogo precisar usar exceções de arredondamento ou FPU não padrão, ele deverá salvar e restaurar a palavra de controle de ponto flutuante, e você deve ter certeza de que ele não chama nenhum código externo que não tenha sido provado ser seguro contra esses problemas, incluindo APIs do sistema.

Instalação opcional do Runtime do DirectX

Vários jogos perguntam ao usuário se deseja instalar o DirectX. Isso poderá causar problemas se o usuário assumir que o sistema tem o mais recente redistribuível do DirectX instalado e ignorar a instalação e, posteriormente, a instalação continuar com êxito. Se o jogo exigir uma versão específica do D3DX ou outra funcionalidade atualizada que não foi instalada, o jogo não funcionará e o usuário ficará muito frustrado.

É altamente recomendável que o instalador do jogo instale silenciosamente o redistribuível do DirectX no qual o jogo foi criado. O processo de instalação do DirectX foi projetado para que ele verifique se algo precisa ser atualizado e retorna rapidamente se não o fizer. Portanto, não é necessário perguntar ao usuário sobre a instalação do DirectX.

Uma instalação silenciosa do DirectX pode ser feita executando este comando do pacote de instalação: dxsetup.exe /silent

Além disso, o tamanho real da pasta redistribuível pode ser configurado para incluir apenas os arquivos de gabinete (.cab) que são realmente necessários para as plataformas de destino e o uso do jogo.

Observação

Antes de usar dxsetup, leia Configuração Não Tão Direta.

 

Uso excessivo de sincronização de thread

Ao criar perfis de jogos, os principais hotspots geralmente são encontrados relacionados à inserção e à saída de seções críticas. Com a prevalência de CPUs de vários núcleos, o uso de multithreading em jogos aumentou drasticamente e muitas implementações dependem do uso intenso da sincronização de threads. O tempo de CPU para fazer uma seção crítica mesmo sem qualquer contenção é bastante significativo e todas as outras formas de sincronização de thread são ainda mais caras. Portanto, deve-se tomar cuidado para minimizar o uso desses primitivos.

Uma fonte comum de sincronização excessiva em jogos é o uso de D3DCREATE_MULTITHREADED. Esse sinalizador, ao mesmo tempo em que torna o thread do Direct3D seguro para renderização de vários threads, adota uma abordagem muito conservadora, resultando em alta sobrecarga de sincronização. Os jogos devem evitar esse sinalizador. Em vez disso, arquitete o mecanismo para que toda a comunicação com o Direct3D seja de um único thread e qualquer comunicação entre threads seja tratada diretamente. Para obter mais informações sobre como criar jogos com vários threads, consulte o artigo Codificação para vários núcleos no Xbox 360 e no Microsoft Windows.

Uso do RDTSC

O uso da instrução x86 RDTSC não é recomendado. O RDTSC falha ao calcular corretamente o tempo em alguns esquemas de gerenciamento de energia que alteram a frequência da CPU dinamicamente e em muitas CPUs de vários núcleos para as quais o contador de ciclo não é sincronizado entre núcleos. Em vez disso, os jogos devem usar a API QueryPerformanceCounter . Para obter mais informações sobre problemas com RDTSC e implementação de tempo de alta resolução com QueryPerformanceCounter, consulte o artigo Tempo de jogo e processadores multicore.