Kata Pengantar
Apa itu GPU ?
Graphics Processing Unit (GPU) adalah suatu perangkat yang didesain untuk rendering grafis yang akan ditampilkan oleh komputer. GPU dioptimalkan untuk melakukan rendering grafis sehingga GPU didesain untuk dapat mengerjakan hal-hal secara paralel lebih banyak. Namun seiring berkembangnya arsitektur GPU, GPU kini dapat juga digunakan untuk mengerjakan pekerjeaan selain rendering grafis. GPU kini tidak hanya digunakan untuk mengerjakan pekerjaan grafis namun juga hal-hal lain seperti machine learning, simulasi fisika, generasi medan, dan lain-lain.
Perbedaan GPU dan CPU
Perbedaan Graphics Processing Unit (GPU) dan Central Processing Unit (CPU) adalah desain dari kedua unit prosessor tersebut. CPU didesain untuk mengerjakan pekerjaan secara urut dan cepat, oleh karena itu CPU mempunyai jumlah unit penghitung yang lebih sedikit dibanding GPU. Meskipun begitu, GPU tidak didesain untuk mengerjakan pekerjaan yang mempunyai cabang. Ini dikarenakan GPU didesain untuk mengerjakan perintah sama ke banyak data dengan cepat. Perbedaan kedua unit prosessor tersebut dibahas lebih panjang disini.
Apa itu Unity ?
Unity adalah suatu aplikasi yang membantu dalam pembuatan permainan komputer dengan menyediakan kumpulan library yang sudah siap sedia. Dengan menggunakan Unity, pembuat permainan tidak perlu membuat kode rendering sendiri namun diberikan kebebasan apabila ingin mengubah cara Unity melakukan rendering. Selain itu, Unity juga menyediakan physics engine, audio engine, dan lainnya. Pada 2020 ini, pembuat aplikasi yang menggunakan Unity mencapai 1.5 juta pengguna sedangkan pengguna dari aplikasi yang dibuat menggunakan Unity mencapai 2 miliar pengguna.
Tutorial
Simulasi basic di CPU
Sebagai tutorial sederhana, kita akan membuat simulasi partikel di ruang hampa di Unity. Kita akan membandingkan aplikasi yang disimulasikan menggunakan CPU simulasi menggunakan GPU. Selain itu, kita juga akan belajar cara menggunakan Compute Shader untuk memindahkan pekerjaan CPU yang dapat dilakukan secara paralel.
Sebelum kita belajar memindahkan pekerjaan CPU ke GPU, mari buat project terlebih dahulu. Agar project yang dibuat sederhana, maka kita akan membuat project dua dimensi saja. Untuk membuat project dua dimensi, dapat buka Unity Hub lalu klik New Project. Setelah klik New Project, pilih konfigurasi 2D dan isi Project Name lalu klik Create Project seperti pada gambar berikut.


Setelah membuat project, buatlah folder dengan nama Sprites untuk mengorganisir isi file project nanti. Untuk membuat project klik kanan di Project View lalu Create > Folder.


Setelah itu, masuk ke folder Sprites dan buat sprite dengan klik kanan di Project View lalu Create > 2D > Sprites > Circle. Beri nama yang sesuai, disini saya akan memberi nama “Circle” seperti pada gambar berikut.



Setelah membuat sprite tersebut, kita akan drag and drop di scene untuk membuat Game Object dengan grafis lingkaran.

Setelah itu kita akan membuat 2 script, yang pertama adalah Particle.cs dan ParticleSimulator.cs. Kelas Particle akan berfungsi sebagai actor object yang menyimpan posisi, kecepatan dan radius. Kelas Particle Simulator akan bertugas untuk memunculkan object dan mensimulasikannya tiap frame. Untuk membuat script, klik kanan di Project View lalu Create > C# Scripts.

Kelas Particle akan berisi seperti berikut
Kelas ParticleSimulator akan berisi berikut
Setelah membuat kedua script, pada object circle yang ada di scene ubah ukurannya menjadi 0.05 untuk sumbu x dan y. Tambahkan juga script Particle.cs dengan properti radius diubah menjadi 0.025. Untuk menambahkan komponen (script) ke game object, pertama klik game object yang ingin ditambahkan komponen (dapat juga klik dari hierarchy). Lalu, klik Add Component dan tambahkan script Particle.



Setelah itu, tarik object tersebut ke Project View untuk membuat prefab.

Setelah itu, buatlah objek kosong dan tambahkan script ParticleSimulator.cs. Masukkan prefab ke properti Object Template, isi Object Speed menjadi 5, dan isi Object To Simulate 10000.


Jalankan gamenya dan lihatlah simulasi di CPU. Coba cek performa dengan membuka stats tab diatas Game View.

dapat dilihat rata-rata FPS pada simulasi menggunakan CPU adalah 11 FPS dan waktu tiap frame mencapai 88.2 ms. Selanjutnya kita akan mencoba untuk memindahkan jobnya ke GPU.
Pemindahan Pekerjaan ke GPU
Untuk memindahkan pekerjaan dari CPU ke GPU, pertama dibutuhkan untuk membuat Compute Shader. Sebelum kita membuat Compute Shader, pertama saya akan menjelaskan apa itu Shader. Jadi Graphics Processing Unit mempunyai tugas untuk melakukan rendering grafis. Graphics Processing Unit menggunakan shader untuk mengetahui bagaimana cara untuk me-render grafis tersebut. Sebagai contoh, Unity mempunyai banyak built-in Shader seperti berikut.

Berbeda dengan Shader tersebut, Compute Shader digunakan untuk melakukan komputasi secara umum. Compute Shader tidak mempunyai input parameter atau output parameter sehingga untuk mempunyai input atau output digunakan Compute Buffer. Setelah kita melakukan pemrosesan data di Compute Shader, kita dapat mengambil data dari buffer dalam bentuk array sehingga dapat digunakan oleh CPU. Berikut merupakan flowchart atau diagram yang menjelaskan cara kerja pembagian kerja di GPU yang akan kita kerjakan nanti.

Compute Shader dapat dibuat dengan klik kanan di Project View lalu Create > Shader > Compute Shader.

Kita akan beri nama Compute Shader tersebut Simulator. Kode compute shader dapat diakses disini
Berikut merupakan pembagian struktur kode tersebut.

Kernel declaration digunakan untuk mendefinisikan fungsi yang akan dijadikan kernel untuk dipanggil oleh CPU. Selanjutnya ada buffer dan variable, disini kita mendefinisikan apa buffer yang digunakan, variable yang digunakan, dll. StructuredBuffer tersebut nanti akan disambungkan dengan Compute Buffer yang dibuat oleh CPU. Selain itu, perhatikan juga struct yang digunakan karena nanti pada CPU, kita harus membuat struct dengan data type yang sama. Setelah itu ada numthread, penjelasan numthread lumayan rumit sehingga akan ada paragraf sendiri nantinya. Terakhir ada main kernel logic, main kernel logic akan berisi semua pemrosesan data yang akan digunakan. Disini kita mempunyai logic yang sama dengan yang ada di CPU. Hasil simulasi ini akan langsung diganti di buffer particles, sehingga nanti bisa diambil oleh CPU.
Konfigurasi numthread digunakan untuk mendefinisikan bagaimana cara kerja kernel akan didistribusikan. Dengan konfigurasi tersebut, kita dapat membuat kernel mengeksekusi 128 thread sekaligus ataupun mempunyai indexing 3 dimensional. Karena cara kerja GPU, komunikasi antar thread group sangat tidak dianjurkan. Namun karena simulasi yang digunakan sangat sederhana, jadi saya akan memberikan 64 karena rekomendasi dari NVDIA dan AMD adalah jumlah thread dalam satu wavefront. Jika ingin belajar numthreads lebih lanjut dapat juga membaca artikel ini.
Selain itu, compute shader juga dapat mempunyai global variable. Pada program simulasi ini, global variable digunakan untuk jumlah objek dan delta time. Berbeda dengan buffer, global variable tidak dibatasi pada kernel tertentu melainkan dapat diakses oleh semuanya.
Pada kernel Simulate, kita akan memasukkan logika simulasi yang awalnya di CPU. Pada dasarnya, kernel nanti akan dikerjakan untuk setiap partikel. id.x akan berisi id untuk satu partikel. Logika simulasi kurang lebih sama dengan logika yang ada di CPU.
Sekarang saatnya melakukan setup script untuk menjalankan Compute Shader. Buatlah script ParticleSimulatorGPU.cs yang bertugas untuk melakukan simulasi partike menggunakan GPU. Isi scriptnya akan berisi seperti berikut.
Pada kode tersebut, saya akan menjelaskan bagian pentingnya saja karena pada dasarnya logicnya sama dengan yang ada di diagram sebelumnya.

Disini, terdapat definisi struct yang ada di compute shader sebelumnya. Selanjutnya ada struct size, ini adalah besar struct dalam besaran byte. Selanjutnya dada definisi buffer dan array, disni list digunakan untuk menyimpan data dengan referensi ke particlenya, array digunakan untuk mengatur data buffer dan mengambil data dari buffer. Lalu terakhir ada ComputeBuffer yang akan kita gunakan sebagai buffer di compute shader kita nanti. Lalu ada bagian ComputeShader dan id cache, disini kita dapat mereferensikan ComputeShader dari editor dan menyimpan id dari ComputeShader.

Pada fungsi start, kita akan mendefinisikan compute buffer dan arraynya. Disini kernelId dan deltaTimeId juga didefinisikan agar tidak perlu mencari idnya lagi. SetBuffer berfungsi untuk meng-assign Compute Buffer ke Compute Shader.

Bagian pertama bertugas untuk mengatur data object ke GPU. Caranya adalah pertama kita memasukkan data yang ingin dikirim ke array struct yang sudah dibuat. Setelah itu kita dapat mengambil fungsi SetData dari ComputeBuffer.
Bagian kedua dispatch bertugas untuk melakukan proses data di GPU. Sebelum itu kita mengatur waktu deltaTime update, sesuai dengan waktu yang ada di Time.deltaTime.
Bagian ketiga bertugas untuk mengambil data dari buffer lalu memperbarui posisi dan kecepatan object yang lain.
Setelah itu, masukkan prefab ke properti Object Template, isi Object Speed menjadi 5, dan isi Object To Simulate 10000.

Jalankan gamenya dan lihatlah simulasi di GPU. Coba cek performa dengan membuka stats tab diatas Game View.

Dapat dilihat dari performa tersebut, simulasi menggunakan GPU mendapatkan 15.7 FPS dan 63.6 ms. Ini terjadi peningkatan 43% dibanding performa CPU yaitu 11 FPS dan 88.2 ms.
Pembaca juga bisa bermain jumlah objek yang disimulasikan dengan mengubah variable Object To Simulate di Particle Simulatornya.
Sekian dari saya, terima kasih sudah membaca artikel ini dan semoga bermanfaat.
Apabila ingin mengakses repository project dapat juga klik link dibawah ini