Programação de 64 bits para desenvolvedores de jogos
Os fabricantes de processadores estão enviando exclusivamente processadores de 64 bits em seus computadores desktop e até mesmo os chipsets da maioria dos computadores laptop dão suporte à tecnologia x64. É importante que os desenvolvedores de jogos aproveitem as melhorias que os processadores de 64 bits oferecem com seus novos aplicativos e garantam que seus aplicativos anteriores sejam executados corretamente nos novos processadores e nas edições de 64 bits do Windows Vista e do Windows 7. Este artigo aborda problemas de portabilidade e compatibilidade e ajuda os desenvolvedores a facilitar a transição para plataformas de 64 bits.
Atualmente, a Microsoft tem os seguintes sistemas operacionais de 64 bits:
- Windows 10
- Windows 11
- Windows Server 2019 ou posterior
Sistemas operacionais de 64 bits anteriores:
- Windows Server 2003 Service Pack 1
- Windows XP Professional x64 Edition (disponível para OEMs e para desenvolvedores por meio do MSDN)
- Windows Vista
- Windows 7
- Windows 8.0
- Windows 8.1
- Windows Server 2008 – 2016
Observação
O Windows Server 2008 R2 ou posterior só está disponível como uma edição de 64 bits. Windows 11 só está disponível como uma edição ARM64 ou de 64 bits.
- Diferenças na memória endereçável
- Especificando reconhecimento de endereço grande ao compilar
- Compatibilidade de aplicativos de 32 bits em plataformas de 64 bits
- Portabilidade de aplicativos para plataformas de 64 bits
- Criação de perfil e otimização de aplicativos portados
- Código gerenciado em um sistema operacional de 64 bits
- Implicações de desempenho da execução de um sistema operacional de 64 bits
- Resumo
Diferenças na memória endereçável
A primeira coisa que a maioria dos desenvolvedores percebe é que os processadores de 64 bits fornecem um grande salto na quantidade de memória física e virtual que pode ser resolvida.
Aplicativos de 32 bits em plataformas de 32 bits podem lidar com até 2 GB.
Aplicativos de 32 bits criados com o sinalizador de vinculador /LARGEADDRESSAWARE:YES no Windows XP de 32 bits ou no Windows Server 2003 com a opção de inicialização especial de /3 gb podem resolver até 3 GB. Isso restringe o kernel a apenas 1 GB, o que pode causar falha em alguns drivers e/ou serviços.
Aplicativos de 32 bits criados com o sinalizador de vinculador /LARGEADDRESSAWARE:YES nas edições de 32 bits do Windows Vista, Windows Server 2008 e Windows 7 podem lidar com a memória até o número especificado pelo elemento de dados de configuração de inicialização (BCD) IncreaseUserVa. IncreaseUserVa pode ter um valor que varia de 2048, o padrão, a 3072 (que corresponde à quantidade de memória configurada pela opção de inicialização /3gb no Windows XP). O restante de 4 GB é alocado para o kernel e pode resultar em configurações de driver e serviço com falha.
Para obter mais informações sobre BCD, consulte Dados de configuração de inicialização.
Aplicativos de 32 bits em plataformas de 64 bits podem lidar com até 2 GB ou até 4 GB com o sinalizador de vinculador /LARGEADDRESSAWARE:YES.
Os aplicativos de 64 bits usam 43 bits para endereçamento, que fornece 8 TB de endereço virtual para aplicativos e 8 TB reservados para o kernel.
Além da memória, aplicativos de 64 bits que usam E/S de arquivo mapeado na memória se beneficiam muito do aumento do espaço de endereço virtual. A arquitetura de 64 bits também melhorou o desempenho de ponto flutuante e a passagem mais rápida de parâmetros. Os processadores de 64 bits têm o dobro do número de registros dos tipos SSE (extensões SIMD de uso geral) e streaming, bem como suporte para conjuntos de instruções SSE e SSE2; muitos processadores de 64 bits até dão suporte a conjuntos de instruções SSE3.
Especificando reconhecimento de endereço grande ao compilar
É uma boa prática especificar aplicativos com reconhecimento de endereço grande ao criar aplicativos de 32 bits usando o sinalizador de vinculador /LARGEADDRESSAWARE, mesmo que o aplicativo não se destine a uma plataforma de 64 bits, devido às vantagens que são obtidas sem custo. Conforme explicado anteriormente, habilitar esse sinalizador para um build permite que um programa de 32 bits acesse mais memória com opções especiais de inicialização em um sistema operacional de 32 bits ou em um sistema operacional de 64 bits. No entanto, os desenvolvedores devem ter cuidado para que as suposições de ponteiro não sejam feitas, como supondo que o bit alto nunca seja definido em um ponteiro de 32 bits. Em geral, habilitar o sinalizador /LARGEADDRESSAWARE é uma boa prática.
Aplicativos de trinta e dois bits com reconhecimento de endereço grande podem determinar em tempo de execução quanto espaço de endereço virtual total está disponível para eles com a configuração atual do sistema operacional chamando GlobalMemoryStatusEx. O resultado ullTotalVirtual variará de 2147352576 bytes (2 GB) a 4294836224 bytes (4 GB). Valores maiores que 3221094400 (3 GB) só podem ser obtidos em edições de 64 bits do Windows. Por exemplo, se IncreaseUserVa tiver um valor de 2560, o resultado será ullTotalVirtual com um valor de 2684223488 bytes.
Compatibilidade de aplicativos de 32 bits em plataformas de 64 bits
Os sistemas operacionais Windows de sessenta e quatro bits são compatíveis binários com a arquitetura IA32 e a maioria das APIs que os aplicativos de 32 bits usam estão disponíveis por meio do Emulador do Windows de 32 bits no Windows de 64 bits, WOW64. WOW64 ajuda a garantir que essas APIs funcionem conforme o esperado.
WOW64 tem uma camada de execução que manipula o marshalling de dados de 32 bits. O WOW64 redireciona solicitações de arquivo DLL, redireciona alguns branches do Registro para aplicativos de 32 bits e reflete alguns branches do Registro para aplicativos de 32 e 64 bits.
Mais informações sobre WOW64 podem ser encontradas em Detalhes da Implementação do WOW64.
Possíveis armadilhas de compatibilidade
A maioria dos aplicativos desenvolvidos para uma plataforma de 32 bits será executada sem problemas em uma plataforma de 64 bits. Alguns aplicativos podem ter problemas, o que pode incluir o seguinte:
- Todos os drivers para edições de 64 bits de sistemas operacionais Windows devem ser versões de 64 bits. Exigir novos drivers de 64 bits tem implicações para esquemas de proteção de cópia que dependem de drivers antigos. Observe que os drivers de modo kernel devem ser assinados por Authenticode para serem carregados por edições de 64 bits do Windows.
- Os processos de 64 bits não podem carregar DLLs de 32 bits e os processos de 32 bits não podem carregar DLLs de 64 bits. Os desenvolvedores devem garantir que as versões de 64 bits de DLLs de terceiros estejam disponíveis antes de prosseguir com o desenvolvimento. Se você precisar usar uma DLL de 32 bits em um processo de 64 bits, a IPC (comunicação entre processos) do Windows poderá ser usada. Os componentes COM também podem usar servidores fora de processo e marshaling para se comunicar entre limites, mas isso pode introduzir uma penalidade de desempenho.
- Muitos processadores x64 também são processadores de vários núcleos, e os desenvolvedores precisam testar como isso afeta seus aplicativos herdados. Mais informações sobre processadores de vários núcleos e as implicações para aplicativos de jogos podem ser encontradas em Tempo de Jogo e Processadores Multicore.
- Os aplicativos também devem chamar SHGetFolderPath para descobrir caminhos de arquivo, pois alguns nomes de pastas foram alterados em determinados casos. Por exemplo, CSIDL_PROGRAM_FILES retornaria "C:\Arquivos de Programas(x86)" para um aplicativo de 32 bits em execução em uma plataforma de 64 bits em vez de "C:\Arquivos de Programas". Os desenvolvedores devem estar atentos a como os recursos de redirecionamento e reflexão do emulador WOW64 funcionam.
Além disso, os desenvolvedores precisam ter cuidado com programas de 16 bits que ainda podem estar usando. O WOW64 não pode lidar com aplicativos de 16 bits; isso inclui instaladores antigos e todos os programas MS-DOS.
Observação
Os problemas de compatibilidade mais comuns são instaladores que executam código de 16 bits e não têm drivers de 64 bits para esquemas de proteção de cópia.
A próxima seção discute problemas relacionados à portabilidade de código para o nativo de 64 bits para desenvolvedores que desejam garantir que seus programas herdados funcionem em plataformas de 64 bits. Também é para desenvolvedores que não estão familiarizados com a programação de 64 bits.
Portabilidade de aplicativos para plataformas de 64 bits
Ter as ferramentas e bibliotecas certas ajudará a facilitar a transição do desenvolvimento de 32 bits para 64 bits. O SDK do DirectX 9 tem bibliotecas para dar suporte a projetos baseados em x86 e x64. O Microsoft Visual Studio 2005 e o Visual Studio 2008 dão suporte à geração de código para x86 e x64 e vêm com bibliotecas otimizadas para gerar código x64. No entanto, também será necessário que os desenvolvedores distribuam os runtimes do Visual C com seus aplicativos. Observe que as Edições Express do Visual Studio 2005 e do Visual Studio 2008 não incluem o compilador x64, mas que todas as edições Standard, Professional e Team System incluem.
Os desenvolvedores direcionados a plataformas de 32 bits podem se preparar para o desenvolvimento de 64 bits para facilitar a transição posteriormente. Ao compilar projetos de 32 bits, os desenvolvedores devem usar o sinalizador /Wp64, o que causará a geração de avisos sobre problemas que afetam a portabilidade. Alternar para ferramentas e bibliotecas de 64 bits provavelmente gerará muitos novos erros de build inicialmente; Portanto, é aconselhável alternar ferramentas e bibliotecas neutras em bits e corrigir quaisquer avisos antes de alternar para um build de 64 bits.
No entanto, alterar ferramentas, alterar bibliotecas e usar determinados sinalizadores do compilador não será suficiente. As suposições nos padrões de codificação devem ser reavaliadas para garantir que os padrões de codificação atuais não permitam problemas de portabilidade. Os problemas de portabilidade podem incluir truncamento de ponteiro, tamanho e alinhamento de tipos de dados, dependência de DLLs de 32 bits, uso de APIs herdadas, código de assembly e arquivos binários antigos.
Observação
O Visual C++ 2010 ou posterior inclui os cabeçalhos stdint.h e cstdint C99 que definem os tipos de portabilidade padrão int32_t, uint32_t, int64_t, uint64_t, intptr_t e uintptr_t. Usá-los juntamente com os tipos de dados padrão ptrdiff_t e size_t podem ser preferíveis aos tipos de portabilty do Windows usados abaixo para melhorar a portabilidade do código.
Os principais problemas de portabilidade incluem o seguinte:
-
Truncamento de ponteiro
-
Os ponteiros são de 64 bits em um sistema operacional de 64 bits, portanto, a conversão de ponteiros para outros tipos de dados pode resultar em truncamento e aritmética de ponteiro pode resultar em corrupção. O uso do sinalizador /Wp64 geralmente fornecerá um aviso sobre esse tipo de problema, mas usar tipos polimórficos (INT_PTR, DWORD_PTR, SIZE_T, UINT_PTR e assim por diante) ao converter tipos de ponteiro é uma boa prática para ajudar a evitar esse problema completamente. Como os ponteiros são de 64 bits em novas plataformas, os desenvolvedores devem marcar a ordenação de ponteiros e os tipos de dados em classes e estruturas, para reduzir ou eliminar o preenchimento.
-
Tipos de dados e arquivos binários
-
Enquanto os ponteiros aumentam de 32 bits para 64 em uma plataforma de 64 bits, outros tipos de dados não. Tipos de dados de precisão fixa (DWORD32, DWORD64, INT32, INT64, LONG32, LONG64, UINT32, UINT64) podem ser usados em locais onde o tamanho do tipo de dados deve ser conhecido; por exemplo, em uma estrutura de arquivo binário. As alterações no tamanho do ponteiro e no alinhamento de dados exigem tratamento especial para garantir a compatibilidade de 32 bits para 64 bits. Mais informações podem ser encontradas em Novos Tipos de Dados.
-
APIs e alinhamento de dados mais antigos do Win32
-
Algumas APIs win32 foram preteridas e substituídas por chamadas de API mais neutras, como SetWindowLongPtr no lugar de SetWindowLong.
A penalidade de desempenho para acessos não alinhados é maior na plataforma x64 do que em uma plataforma x86. As macros TYPE_ALIGNMENT(t) e FIELD_OFFSET(t, member) podem ser usadas para determinar informações de alinhamento que podem ser usadas diretamente pelo código. O uso correto dessas macros mencionadas acima deve eliminar possíveis penalidades de acesso não alinhadas.
Mais informações sobre a macro TYPE_ALIGNMENT, a macro FIELD_OFFSET e informações gerais de programação de 64 bits podem ser encontradas em Programação do Windows de 64 bits: Dicas de migração: considerações adicionais e regras para usar ponteiros.
-
Código do assembly
-
O código de assembly embutido não tem suporte em plataformas de 64 bits e precisa ser substituído. As alterações na arquitetura podem ter alterado os gargalos do aplicativo, e C/C++ ou intrínsecos podem obter resultados semelhantes com código mais fácil de ler. A prática mais aconselhável é alternar todo o código do assembly para C ou C++. Intrínsecos podem ser usados no lugar do código do assembly, mas só devem ser usados depois que a criação de perfil e a análise completas forem executadas.
O x87, MMX e 3DNow! os conjuntos de instruções são preteridos em modos de 64 bits. Os conjuntos de instruções ainda estão presentes para compatibilidade com versões anteriores para o modo de 32 bits; no entanto, para evitar problemas de compatibilidade no futuro, seu uso em projetos atuais e futuros é desencorajado.
-
APIs preteridas
-
Algumas APIs DirectX mais antigas foram descartadas para aplicativos nativos de 64 bits: DirectPlay 4 e anterior, DirectDraw 6 e anterior, Direct3D 8 e anterior e DirectInput 7 e anterior. Além disso, a API principal do DirectMusic está disponível para aplicativos nativos de 64 bits, mas a camada de desempenho e o Produtor DirectMusic foram preteridos.
O Visual Studio emite avisos de substituição e essas alterações não são um problema para desenvolvedores que usam as APIs mais recentes.
Criação de perfil e otimização de aplicativos portados
Todos os desenvolvedores precisam recriar o perfil de todos os aplicativos que estão sendo portados para novas arquiteturas. Muitos aplicativos portados para plataformas de 64 bits terão perfis de desempenho diferentes de suas versões de 32 bits. Os desenvolvedores precisam executar testes de desempenho de 64 bits antes de avaliar o que precisa ser otimizado. A boa notícia sobre isso é que muitas otimizações tradicionais funcionam em plataformas de 64 bits. Além disso, os compiladores de 64 bits também podem executar muitas otimizações com o uso correto de sinalizadores do compilador e dicas de codificação.
Algumas estruturas podem ter seus tipos de dados internos reordenados para conservar o espaço de memória e melhorar o cache. Índices de matriz podem ser usados em vez de um ponteiro completo de 64 bits em alguns casos. O sinalizador /fp:fast pode melhorar a otimização e a vetorização de ponto flutuante. Usar __restrict, declspec(restrict) e declspec(noalias) pode ajudar o compilador resolve aliasing e melhorar o uso do arquivo de registro.
Mais informações sobre /fp:fast podem ser encontradas em /fp (Especificar Floating-Point Comportamento).
Mais informações sobre __restrict podem ser encontradas em Modificadores Específicos da Microsoft.
Mais informações sobre declspec(restrict) podem ser encontradas em Práticas Recomendadas de Otimização.
Mais informações sobre declspec(noalias) podem ser encontradas em __declspec(noalias).
Código gerenciado em um sistema operacional de 64 bits
O código gerenciado é usado por muitos desenvolvedores de jogos em sua cadeia de ferramentas, portanto, uma compreensão de como ele se comporta em um sistema operacional de 64 bits pode ser útil. O código gerenciado é neutro no conjunto de instruções, portanto, quando você executa um aplicativo gerenciado em um sistema operacional de 64 bits, o CLR (Common Language Runtime) pode executá-lo como um processo de 32 bits ou 64 bits. Por padrão, o CLR executa aplicativos gerenciados como de 64 bits e eles devem funcionar bem sem problemas. No entanto, se o aplicativo depender de uma DLL nativa de 32 bits, o aplicativo falhará quando tentar chamar essa DLL. Um processo de 64 bits precisa de um código completamente de 64 bits e uma DLL de 32 bits não pode ser chamada de um processo de 64 bits. A melhor solução de longo prazo é compilar seu código nativo como de 64 bits também, mas uma solução de curto prazo perfeitamente razoável é simplesmente marcar seu aplicativo gerenciado como sendo para x86 apenas usando o sinalizador de build /platform:x86.
Implicações de desempenho da execução de um sistema operacional de 64 bits
Como os processadores com arquitetura AMD64 e Intel 64 podem executar instruções de 32 bits nativamente, eles podem executar aplicativos de 32 bits a toda velocidade, mesmo em um sistema operacional de 64 bits. Há um custo modesto para converter parâmetros entre 32 e 64 bits ao chamar funções do sistema operacional, mas esse custo geralmente é insignificante. Isso significa que você não deve ver nenhuma desaceleração ao executar aplicativos de 32 bits em um sistema operacional de 64 bits.
Quando você compila aplicativos como de 64 bits, os cálculos ficam mais complicados. Um programa de 64 bits usa ponteiros de 64 bits e suas instruções são um pouco maiores, portanto, o requisito de memória é ligeiramente aumentado. Isso pode causar uma pequena queda no desempenho. Por outro lado, ter o dobro de registros e ter a capacidade de fazer cálculos inteiros de 64 bits em uma única instrução geralmente compensará mais do que. O resultado líquido é que um aplicativo de 64 bits pode ser executado um pouco mais lento do que o mesmo aplicativo compilado como 32 bits, mas geralmente será executado um pouco mais rápido.
Resumo
As arquiteturas de sessenta e quatro bits permitem que os desenvolvedores efetuem push das limitações de aparência, som e reprodução dos jogos. No entanto, a transição da programação de 32 bits para a programação de 64 bits não é trivial. Ao entender as diferenças entre os dois e usando as ferramentas mais recentes, a transição para plataformas de 64 bits pode ser mais fácil e rápida.
Mais informações sobre programação de 64 bits podem ser encontradas no Centro de Desenvolvedores do Visual C++: Programação de 64 bits.