Prólogo
Buen día, hablaremos sobre el motor del juego X-Ray, o más bien, sobre su tenedor de X-Ray Oxygen. En diciembre de 2016, se publicó el proyecto X-Ray Oxygen. Luego lo desarrollé solo y no soñé con lo que se ha convertido en este momento.
En marzo, se me ocurrió la idea: "¿Por qué no transferirlo todo a x64?" Como comprenderá, se tratará esta idea, o más bien su implementación.
Asamblea de proyecto
El primer paso fue portar el código para colocar todo bajo la plataforma x64. Después de configurar proyectos, me encontré con el primer problema ... No, no las funciones de Ptr, pero las inserciones de ensamblador ...
__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 belleza de este código fue la optimización, pero MSBuilder en x64 no lo admitió y aún no lo admite. La mayor parte de este código podría reemplazarse por análogos estándar, había lugares que podían cambiarse fácilmente a intrínsecos , por ejemplo, como:
__asm pause;
Podría ser reemplazado de manera segura por:
_mm_pause();
También en el motor, a veces había funciones análogas en el código nativo (Alabado sea el sistema CPUID). Pero había lugares de los que tenías que deshacerte. Por ejemplo, las instrucciones MMX se han hundido en el olvido. Afortunadamente, no fueron llamados a ninguna parte, sino que simplemente se compilaron y permanecieron inactivos.
Operabilidad
Después de todas las ediciones en el ensamblaje, la siguiente etapa ha comenzado: ¿Cómo comenzar todo esto?
El primer traidor fue LuaJIT . Desafortunadamente, LuaJIT comenzó a funcionar bien (bueno, casi ...) en x64 solo con la versión 2.0.5. Y esos fueron pequeños problemas con la asignación de memoria de dígitos pequeños. Pero, entonces no lo sabía y lo primero que vi fue LuaJIT y la vainilla Lua 5.1. Sí, esto solucionó el problema, pero la velocidad ... Recuerde, lamentamos. Más adelante en el foro me informaron que puede intentar usar LuaJIT 2.0.4. Y sí, ayudó, ¡comencé el juego y pude ir al menú principal!
Pero ... La felicidad duró poco ... Hola para estructurar compensaciones, tipos de datos y xrCDB. El juego no cargó el nivel, los materiales volaron hacia los objetos y al motor no le gustó mucho. Después de un par de días, me desesperé por completo y decidí pedir ayuda a un programador más experimentado bajo el apodo de Giperion. No conté con su participación en el proyecto, mi sueño era solo un consejo. Pero, de esta manera, conseguí un desarrollador experimentado en el proyecto. A partir de ese momento, se formó un equipo.
El siguiente problema fue OPCODE y tipos de datos. Tuve que traducir todas las udwords (unsigned int) a uqwords (unsigned long long). Solo para entender esto, tuve que pasar unas 4 horas bajo el depurador.
Pero, eso era solo una parte del problema. Fue el turno de los materiales. Que tenemos
union { u32 dummy;
Tal código en x32 fue guardado por magic #pragma pack(4)
, pero por x64 por alguna razón no lo guardó. Llegó el turno de la alineación, mediante una depuración descubrimos que para algunos casos los datos en la estructura eran válidos, pero para otros no. Rediseñamos la estructura e hicimos el convertidor validador. La estructura tiene la siguiente forma:
union { size_t dummy; struct { size_t material:14;
Y el validador era así:
... 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)); } ...
Por lo tanto, parte de las llamadas tuvieron que cambiarse debido a la bandera rebuildTrisRequired, pero el juego pudo comenzar.
Pero, con el tiempo, surgió el problema con las partículas:
real_ptr = malloc( sizeof( Particle ) * ( max_particles + 1 ) ); particles = (Particle*)((DWORD)real_ptr + (64 - ((DWORD)real_ptr & 63)));
Este código no causó problemas con las partículas originales. Eran demasiado simples y callados en la memoria asignada para ellos. Pero con detalles más complejos y coloridos, hechos por modmakers, surgieron desviaciones de la memoria. x64 y se bloquea de memoria, ¿cómo es eso? El código ha sido renovado, las salidas se han ido:
particles = alloc<Particle>(max_particles);
Problemas de juego
El primer problema fue, nuevamente, LuaJIT

Volaron datos de usuario para portadas inteligentes. Este problema se ha solucionado casi al final. Simplemente transfiriendo las ediciones del LuaJIT 2.0.5 lanzado.
Siguiente problema: Física y cálculo de flotadores. control87
y _controlfp
para calcular el infinity
en x64 fueron bloqueados ... Hubo un gran problema con la caída de elementos, una vez a tres cayeron correctamente. A veces volaban al espacio, a veces bajo tierra. El problema radica en una sola variable, a la que se le dio el valor infinito. La situación fue arreglada por FLT_MAX, lo mismo para todas las plataformas.
surface.mu = dInfinty
El último problema fue la velocidad de las partículas. Presta atención al siguiente código:
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x); fsincos(angle, sina, cosa); }
Todo parece estar en orden. Pero, 0xFFFFFFFF en x64 tiene un significado diferente cuando se convierte a un tipo de punto flotante. El hecho es que fsincos tiene una contraparte doble, y x64 prefiere datos dobles. Y ese valor en doble importa mucho más. La conversión a flotante salvó la situación.
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x);
Conclusión
En conclusión, solo quiero decir una cosa: el puerto en x64 trajo muchos nuevos conocimientos que serán útiles en el futuro. Te conté sobre muchos problemas de portabilidad. Y luego todo dependerá de usted si decide hacer esto en cualquier proyecto OpenSource.
Gracias por leer!