Como trouxemos o X-Ray x64

Prefácio


Bom dia, falaremos sobre o mecanismo de jogo de raios-X, ou melhor, sobre o garfo de oxigênio para raios-X Em dezembro de 2016, o projeto de oxigênio para raios-X foi publicado. Então eu a desenvolvi sozinha e não sonhei com o que se tornou no momento.


Em março, surgiu a idéia: "Por que não transferir tudo para x64?" Como você entende, é sobre essa idéia, ou melhor, sobre sua implementação, que será discutida.


Montagem do projeto


O primeiro passo foi portar o código para colocar tudo sob a plataforma x64. Depois de configurar os projetos, encontrei o primeiro problema ... Não, não as funções do Ptr, mas o assembler insere ...


__forceinline void fsincos( const float angle , float &sine , float &cosine ) { __asm { fld DWORD PTR [angle] fsincos mov eax , DWORD PTR [cosine] fstp DWORD PTR [eax] mov eax , DWORD PTR [sine] fstp DWORD PTR [eax] } } 

A beleza desse código era a otimização, mas o MSBuilder em x64 não o suportava e ainda não o suporta. A maior parte desse código pode ser substituída por análogos std; havia lugares que poderiam ser facilmente alterados para Intrínsecos , por exemplo, como:


 __asm pause; 

Pode ser substituído com segurança por:


 _mm_pause(); 

Também no mecanismo, às vezes havia análogos de funções no código nativo (louvado seja o sistema CPUID). Mas havia lugares dos quais você só precisava se livrar. Por exemplo, as instruções da MMX caíram no esquecimento. Felizmente, eles não foram chamados a lugar algum, mas simplesmente compilados e permanecendo ociosos.


Operabilidade


Depois de todas as edições na montagem, a próxima etapa começou: Como começar tudo isso?


O primeiro traidor foi LuaJIT . Infelizmente, o LuaJIT começou a funcionar bem (bem, quase ...) no x64 apenas com a versão 2.0.5. E esses eram pequenos problemas com a alocação de memória de pequenos dígitos. Mas, então, eu não sabia e a primeira coisa que vi foi o LuaJIT e enrolei a baunilha Lua 5.1. Sim, isso resolveu o problema, mas a velocidade ... Lembre-se, lamentamos. Mais tarde, no fórum, fui informado de que você pode tentar usar o LuaJIT 2.0.4. E sim, ajudou, eu comecei o jogo e fui capaz de ir para o menu principal!


Mas ... a felicidade durou pouco ... Olá para estruturar compensações, tipos de dados e xrCDB. O jogo não carregou o nível, os materiais voaram nos objetos e o motor não gostou muito. Depois de alguns dias, fiquei completamente desesperada e decidi pedir ajuda a um programador mais experiente, sob o apelido de Giperion. Não contei com a participação dele no projeto, meu sonho era apenas um conselho. Mas, dessa maneira, consegui um desenvolvedor experiente no projeto. A partir desse momento, uma equipe se formou.


O próximo problema foi OPCODE e tipos de dados. Eu tive que traduzir todas as udwords (int sem assinatura) para uqwords (sem assinatura por muito tempo). Somente para entender isso, tive que passar cerca de 4 horas no depurador.


Mas isso foi apenas parte do problema. Foi a vez dos materiais. O que temos:


 union { u32 dummy; // 4b struct { u32 material : 14; // u32 suppress_shadows : 1; // u32 suppress_wm : 1; // u32 sector : 16; // }; }; 

Esse código no x32 foi salvo pelo #pragma pack(4) mágico #pragma pack(4) , mas no x64, por algum motivo, ele não foi salvo. Chegou a vez do alinhamento, por meio de uma depuração, descobrimos que em alguns casos os dados na estrutura eram válidos, mas em outros não. Refazemos a estrutura e tornamos o conversor validador. A estrutura tem o seguinte formato:


 union { size_t dummy; struct { size_t material:14; // size_t suppress_shadows:1; // size_t suppress_wm:1; // size_t sector:16; // size_t dumb : 32; // ,     x64. }; 

E o validador era assim:


 ... if (rebuildTrisRequired) { TRI_DEPRECATED* realT = reinterpret_cast<TRI_DEPRECATED*> (T); for (int triIter = 0; triIter < tris_count; ++triIter) { TRI_DEPRECATED& oldTri = realT[triIter]; TRI& newTri = tris[triIter]; newTri = oldTri; } } else { std::memcpy(tris, T, tris_count * sizeof(TRI)); } ... 

Assim, parte das chamadas teve que ser alterada devido ao sinalizador rebuildTrisRequired, mas o jogo foi iniciado.


Mas, com o tempo, surgiu o problema com as partículas:


 real_ptr = malloc( sizeof( Particle ) * ( max_particles + 1 ) ); particles = (Particle*)((DWORD)real_ptr + (64 - ((DWORD)real_ptr & 63))); 

Este código não causou problemas com as partículas originais. Eles eram muito simples e se encaixavam silenciosamente na memória alocada para eles. Mas, com detalhes mais complexos e coloridos, feitos por modmakers, surgiram desvios da memória. x64 e trava na memória, como assim ?! O código foi refeito, as partidas desapareceram:


 particles = alloc<Particle>(max_particles); 

Problemas de jogo


O primeiro problema foi, novamente, LuaJIT


...


Os dados do usuário para capas inteligentes voaram. Este problema foi corrigido quase o último. Apenas transferindo as edições do LuaJIT 2.0.5 lançado.


Próximo problema: Física e cálculo de carros alegóricos. control87 e _controlfp para calcular o infinity em x64 foram bloqueados ... Houve um grande problema com a queda de itens, uma vez que três deles caíram corretamente. Às vezes eles voavam para o espaço, às vezes sob terrane. O problema estava em apenas uma variável, à qual foi dado o valor infinito. A situação foi corrigida pelo FLT_MAX, o mesmo para todas as plataformas.


 surface.mu = dInfinty // x32 surface.mu = FLT_MAX // x64 

O último problema foi a velocidade das partículas. Preste atenção ao seguinte código:


 DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x); fsincos(angle, sina, cosa); } 

Tudo parece estar em ordem. Mas, 0xFFFFFFFF em x64 tem um significado diferente ao converter para um tipo de ponto flutuante. O fato é que fsincos tem uma contraparte dupla e x64 prefere dados duplos. E esse valor em dobro importa muito mais. Converter para flutuar salvou a situação.


 DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x); // fsincos(angle, sina, cosa); fsincos(*(float*)&angle, sina, cosa); } 

Conclusão


Concluindo, quero dizer apenas uma coisa: a porta em x64 trouxe muitos conhecimentos novos que serão úteis no futuro. Eu falei sobre muitos problemas de portabilidade. E então tudo dependerá de você, se você decidir fazer isso em qualquer projeto OpenSource.


Obrigado pela leitura!

Source: https://habr.com/ru/post/pt421823/


All Articles