Préface
Bonjour, nous parlerons du moteur de jeu X-Ray, ou plutôt de sa fourchette de X-Ray Oxygen En décembre 2016, le projet X-Ray Oxygen a été publié. Puis je l'ai développé seul et je n'ai pas rêvé de ce qu'il est devenu en ce moment.
En mars, l'idée m'est venue: "Pourquoi ne pas tout transférer en x64?" Comme vous le comprenez, c'est à propos de cette idée, ou plutôt de sa mise en œuvre, qui sera discutée.
Montage du projet
La première étape consistait à porter le code pour mettre le tout sous la plate-forme x64. Après avoir configuré des projets, j'ai rencontré le premier problème ... Non, pas des fonctions Ptr, mais des insertions d'assembleur ...
__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] } }
La beauté de ce code était l'optimisation, mais MSBuilder en x64 ne le supportait pas et ne le supporte toujours pas. La plupart de ce code pourrait être remplacé par des analogues std, il y avait des endroits qui pouvaient être facilement modifiés en Intrinsics , par exemple, comme:
__asm pause;
Il pourrait être remplacé en toute sécurité par:
_mm_pause();
Toujours dans le moteur, il y avait parfois des analogues de fonctions sur le code natif (Louange au système CPUID). Mais il y avait des endroits dont vous deviez vous débarrasser. Par exemple, les instructions MMX sont tombées dans l'oubli. Heureusement, ils n'étaient appelés nulle part, mais simplement compilés et restés inactifs.
Opérabilité
Après toutes les modifications sur l'assemblage, la prochaine étape a commencé: comment commencer tout cela?
Le premier traître était LuaJIT . Malheureusement, LuaJIT a commencé à bien fonctionner (enfin, presque ...) en x64 uniquement avec la version 2.0.5. Et ce sont de petits problèmes avec l'allocation de mémoire à partir de petits chiffres. Mais, alors je ne savais pas à ce sujet et la première chose que j'ai vue était LuaJIT et roulé vanilla Lua 5.1. Oui, cela a résolu le problème, mais la vitesse ... Rappelez-vous, nous pleurons. Plus tard sur le forum, j'ai été informé que vous pouvez essayer d'utiliser LuaJIT 2.0.4. Et oui, ça a aidé, j'ai commencé le jeu et j'ai pu aller au menu principal!
Mais ... Le bonheur a été de courte durée ... Bonjour pour structurer les décalages, les types de données et xrCDB. Le jeu n'a pas chargé le niveau, les matériaux ont volé sur les objets et le moteur n'a pas beaucoup aimé. Après quelques jours, j'ai désespéré et j'ai décidé de demander l'aide d'un programmeur plus expérimenté sous le surnom de Giperion. Je ne comptais pas sur sa participation au projet, mon rêve n'était que conseil. Mais, de cette façon, j'ai fait participer un développeur expérimenté au projet. A partir de ce moment, une équipe s'est formée.
Le problème suivant était OPCODE et les types de données. J'ai dû traduire tous les udwords (unsigned int) en uqwords (unsigned long long). Seulement pour comprendre cela, j'ai dû passer environ 4 heures sous le débogueur.
Mais ce n'était qu'une partie du problème. C'était au tour des matériaux. Qu'avons-nous:
union { u32 dummy;
Ce code en x32 a été enregistré par le #pragma pack(4)
magique #pragma pack(4)
, mais pour x64 pour une raison quelconque, il n'a pas été enregistré. Le tour de l'alignement est venu, au moyen d'un débogage, nous avons découvert que dans certains cas, les données de la structure étaient valides, mais pour d'autres non. Nous avons refait la structure et fait le validateur du convertisseur. La structure a la forme suivante:
union { size_t dummy; struct { size_t material:14;
Et le validateur était comme ça:
... 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)); } ...
Ainsi, une partie des appels a dû être modifiée en raison de l'indicateur rebuildTrisRequired, mais le jeu a pu démarrer.
Mais, au fil du temps, le problème avec les particules est venu:
real_ptr = malloc( sizeof( Particle ) * ( max_particles + 1 ) ); particles = (Particle*)((DWORD)real_ptr + (64 - ((DWORD)real_ptr & 63)));
Ce code n'a pas causé de problèmes avec les particules d'origine. Ils étaient trop simples et s'inscrivaient tranquillement dans la mémoire qui leur était allouée. Mais avec des détails plus complexes et colorés, qui ont été faits par des modmakers, des départs de mémoire sont venus. x64 et plantages de mémoire, comment cela?! Le code a été refait, les départs ont disparu:
particles = alloc<Particle>(max_particles);
Problèmes de jeu
Le premier problème était, encore une fois, LuaJIT

Les données utilisateur pour les couvertures intelligentes ont volé. Ce problème a été résolu presque le dernier. Il suffit de transférer les modifications du LuaJIT 2.0.5 publié.
Problème suivant: Physique et calcul des flotteurs. control87
et control87
pour le calcul de l' infinity
en x64 ont été bloqués ... Il y avait un gros problème avec la chute des objets, une à trois ils tombaient correctement. Parfois, ils volaient dans l'espace, parfois sous terrane. Le problème résidait dans une seule variable, à laquelle on a donné la valeur infini. La situation a été corrigée par FLT_MAX, la même pour toutes les plateformes.
surface.mu = dInfinty
Le dernier problème était la vitesse des particules. Faites attention au code suivant:
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x); fsincos(angle, sina, cosa); }
Tout semble être en ordre. Mais, 0xFFFFFFFF en x64 a une signification différente lors de la conversion en un type à virgule flottante. Le fait est que fsincos a une contrepartie Double, et x64 préfère les données doubles. Et cette valeur en double compte beaucoup plus. La conversion en flotteur a sauvé la situation.
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x);
Conclusion
En conclusion, je veux dire une seule chose: le port en x64 a apporté beaucoup de nouvelles connaissances qui seront utiles à l'avenir. Je vous ai parlé de nombreux problèmes de portage. Et puis tout dépendra de vous si vous décidez de le faire dans tous les projets OpenSource.
Merci d'avoir lu!