Kata Pengantar
Selamat siang, kita akan berbicara tentang mesin game X-Ray, atau lebih tepatnya, tentang garpu X-Ray Oxygen Pada bulan Desember 2016, proyek X-Ray Oxygen diterbitkan. Kemudian saya mengembangkannya sendiri dan tidak bermimpi tentang menjadi apa saat ini.
Pada bulan Maret, sebuah ide muncul pada saya: "Mengapa tidak mentransfer semuanya ke x64?" Seperti yang Anda pahami, ini tentang ide ini, atau lebih tepatnya implementasinya, yang akan dibahas.
Perakitan proyek
Langkah pertama adalah porting kode untuk meletakkan semuanya di bawah platform x64. Setelah menyiapkan proyek, saya mengalami masalah pertama ... Tidak, bukan fungsi Ptr, tetapi insert assembler ...
__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] } }
Keindahan kode ini adalah optimasi, tetapi MSBuilder di x64 tidak mendukungnya dan masih tidak mendukungnya. Sebagian besar kode ini dapat diganti dengan analog std, ada tempat-tempat yang dapat dengan mudah diubah menjadi Intrinsics , misalnya, seperti:
__asm pause;
Itu bisa diganti dengan aman oleh:
_mm_pause();
Juga di mesin, kadang-kadang ada analog fungsi pada kode asli (Pujian untuk sistem CPUID). Tetapi ada beberapa tempat yang harus Anda singkirkan. Sebagai contoh, instruksi MMX telah tenggelam terlupakan. Untungnya, mereka tidak dipanggil kemana-mana, tetapi hanya dikompilasi dan berbaring diam.
Operabilitas
Setelah semua suntingan di majelis, tahap selanjutnya telah dimulai: Bagaimana memulai semua ini?
Pengkhianat pertama adalah LuaJIT . Sayangnya, LuaJIT mulai berfungsi dengan baik (well, hampir ...) di x64 hanya dengan versi 2.0.5. Dan itu adalah masalah kecil dengan alokasi memori dari angka kecil. Tapi, kemudian saya tidak tahu tentang hal itu dan hal pertama yang saya lihat adalah LuaJIT dan menggulingkan vanilla Lua 5.1. Ya, ini menyelesaikan masalah, tetapi kecepatan ... Ingat, kami berduka. Kemudian di forum saya diberitahu bahwa Anda dapat mencoba menggunakan LuaJIT 2.0.4. Dan ya, itu membantu, saya memulai permainan dan bisa pergi ke menu utama!
Tapi ... Kebahagiaan berumur pendek ... Halo untuk menyusun offset, tipe data, dan xrCDB. Permainan tidak memuat level, material terbang ke objek dan mesin tidak begitu menyukainya. Setelah beberapa hari, saya benar-benar putus asa dan memutuskan untuk meminta bantuan dari programmer yang lebih berpengalaman dengan nama panggilan Giperion. Saya tidak mengandalkan partisipasinya dalam proyek ini, mimpi saya hanyalah saran. Tapi, dengan cara ini, saya mendapatkan pengembang yang berpengalaman dalam proyek ini. Sejak saat itu, sebuah tim terbentuk.
Masalah selanjutnya adalah OPCODE dan tipe data. Saya harus menerjemahkan semua udwords (unsigned int) ke uqwords (unsigned long long). Hanya untuk memahami ini, saya harus menghabiskan sekitar 4 jam di bawah debugger.
Tapi, itu hanya sebagian dari masalah. Itu adalah pergantian bahan. Apa yang kita miliki:
union { u32 dummy;
Kode seperti itu di x32 disimpan oleh magic #pragma pack(4)
, tetapi untuk x64 karena alasan tertentu tidak disimpan. Pergantian penyelarasan datang, dengan menggunakan debug kami menemukan bahwa untuk beberapa kasus data dalam struktur itu valid, tetapi untuk yang lain tidak. Kami redid struktur dan membuat validator konverter. Struktur memiliki bentuk sebagai berikut:
union { size_t dummy; struct { size_t material:14;
Dan validatornya seperti ini:
... 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)); } ...
Dengan demikian, sebagian dari panggilan harus diubah karena bendera rebuildTrisRequired, tetapi permainan bisa dimulai.
Tapi, seiring waktu, masalah dengan partikel datang:
real_ptr = malloc( sizeof( Particle ) * ( max_particles + 1 ) ); particles = (Particle*)((DWORD)real_ptr + (64 - ((DWORD)real_ptr & 63)));
Kode ini tidak menyebabkan masalah dengan partikel aslinya. Mereka terlalu sederhana dan diam-diam masuk ke memori yang dialokasikan untuk mereka. Tetapi dengan rincian yang lebih kompleks dan berwarna-warni, yang dibuat oleh pembuat mod, keberangkatan dari ingatan datang. x64 dan macet dari memori, bagaimana? ?! Kode telah diulang, keberangkatan hilang:
particles = alloc<Particle>(max_particles);
Masalah gim
Masalah pertama adalah, sekali lagi, LuaJIT

Data pengguna untuk smart cover terbang. Masalah ini telah diperbaiki hampir yang terakhir. Hanya mentransfer suntingan dari LuaJIT 2.0.5 yang dirilis.
Masalah selanjutnya: Fisika dan perhitungan kendaraan hias. control87
dan _controlfp
untuk menghitung infinity
di x64 diblokir ... Ada masalah besar dengan setetes item, setelah tiga item jatuh dengan benar. Terkadang mereka terbang ke luar angkasa, terkadang di bawah terrane. Masalahnya terletak pada hanya satu variabel, yang diberi nilai tak terhingga. Situasi diperbaiki oleh FLT_MAX, sama untuk semua platform.
surface.mu = dInfinty
Masalah terakhir adalah kecepatan partikel. Perhatikan kode berikut:
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x); fsincos(angle, sina, cosa); }
Segalanya tampak teratur. Tapi, 0xFFFFFFFF di x64 memiliki arti berbeda ketika mengkonversi ke tipe floating point. Faktanya adalah bahwa fsincos memiliki pasangan ganda, dan x64 lebih memilih data ganda. Dan nilai ganda lebih penting. Konversi ke pelampung menyelamatkan situasi.
DWORD angle = 0xFFFFFFFF; ... if (angle != *((DWORD*)&m.rot.x)) { angle = *((DWORD*)&m.rot.x);
Kesimpulan
Sebagai kesimpulan, saya hanya ingin mengatakan satu hal: port di x64 membawa banyak pengetahuan baru yang akan berguna di masa depan. Saya katakan tentang banyak masalah porting. Dan semuanya akan tergantung pada Anda jika Anda memutuskan untuk melakukan ini dalam proyek OpenSource apa pun.
Terima kasih sudah membaca!