Tối Ưu Hóa Engine Game Di Động - nói dối e blog

Tối Ưu Hóa Engine Game Di Động

Engine game di động của chúng tôi đã không ngừng được cải tiến song song với tiến trình phát triển dự án game. Lúc đầu, engine gặp vấn đề về hiệu suất khi không đạt được số khung hình mong muốn trên thiết bị di động. Nhờ vào việc áp dụng khung công tác ECS (Entity Component System), chúng tôi đã đạt được bước đột phá khi chuyển đổi một số hệ thống core từ Lua sang C. Dù lượng code core này không quá lớn, nhưng hiệu quả mang lại rất rõ rệt - ví dụ hệ thống cập nhật scene graph vốn tiêu tốn nhiều tài nguyên CPU, sau khi viết lại bằng C với chỉ 200 dòng code, thời gian xử lý giảm từ hơn 1ms xuống gần như không đáng kể so với phiên bản Lua ban đầu.

Chúng tôi cũng áp dụng mô hình đa luồng tương tự ltask/skynet, phân tách các nghiệp vụ phức tạp thành các luồng xử lý song song. Hiện tại, ngoài logic chính, các hệ thống như UI, particle, IO đều được xử lý độc lập trên các luồng riêng biệt. Ngay cả nền tảng render bgfx cũng được thiết kế với kiến trúc đa luồng. Các luồng này chỉ giao tiếp qua lượng thông điệp cực nhỏ, nhờ đó tổng công việc xử lý không tăng so với mô hình đơn luồng. Đặc biệt, ltask giúp dễ dàng điều chỉnh số lượng luồng làm việc để phù hợp với cấu hình CPU của từng thiết bị di động.

Theo dữ liệu từ Xcode, khi xử lý cảnh game phức tạp, hệ thống tiêu thụ khoảng 280% CPU. Điều này cho thấy nếu sử dụng kiến trúc đơn luồng, việc giữ nguyên các tính năng hiện tại mà vẫn đảm bảo mượt mà là điều gần như bất khả thi. Trên thiết bị thử nghiệm iPhone 12 mini của tôi, game hiện tại bị giới hạn ở 30fps với thời gian xử lý trung bình mỗi khung hình khoảng 10ms (dao động từ 7ms đến 15ms). Về mặt lý thuyết, hoàn toàn có thể đạt 60fps, tuy nhiên vì đây không phải game hành động nên không cần thiết phải nâng cao tần suất này.

Vấn đề thách thức lớn nhất hiện tại là vấn đề năng lượng. Đây là trải nghiệm hoàn toàn mới so với việc phát triển trên nền tảng PC. Khi thiết bị di động vận hành ở cường độ cao vượt quá ngưỡng TDP (Thermal Design Power), hiện tượng quá nhiệt sẽ xảy ra khiến CPU tự động giảm xung nhịp. Điều này không chỉ ảnh hưởng đến thời lượng pin mà còn trực tiếp làm giảm chất lượng trải nghiệm người dùng.

Nhận thức này buộc chúng tôi phải thay đổi toàn diện cách tiếp cận tối ưu hóa. Thay vì chỉ tập trung vào chỉ số FPS, chúng tôi giờ đây phải cân nhắc cả yếu tố tiết kiệm năng lượng. Những giải pháp trước đây bị coi là phức tạp như hệ thống cache dữ liệu tính toán để tránh xử lý trùng lặp, hiện nay trở thành lựa chọn ưu tiên dù làm tăng độ phức tạp code nhưng lại giảm đáng kể tải CPU. Ví dụ, có những thuật toán đơn giản dùng cách tính toán lại hoàn toàn mỗi frame, giờ đây cần được tối ưu hóa.

Một điểm đặc biệt là hiệu năng GPU trên di động không thể so sánh với thiết bị chuyên dụng. Dù thông số lý thuyết GPU của iPhone 12 vượt trội hơn nhiều so với Switch (và thậm chí có thể sánh với PS4), nhưng thực tế khả năng tản nhiệt kém khiến hiệu năng đỉnh không thể duy trì lâu dài. Với TDP chỉ 6W so với 15W của Switch, thiết bị di động yêu cầu các nhà phát triển phải có chiến lược tối ưu hóa đặc biệt. Chúng tôi đã áp dụng PBR (Physical Based Rendering) nhưng gặp khó khăn do shader phức tạp tiêu tốn nhiều tài nguyên GPU.

Phân tích chi tiết cho thấy fragment shader là thành phần tiêu thụ nhiều năng lượng nhất. Giải pháp tạm thời là giảm độ phân giải render từ 2388x1128 xuống 1170x560 (50% so với full screen). Thử nghiệm thực tế cho thấy chất lượng hình ảnh chỉ giảm nhẹ nhưng mức tiêu thụ năng lượng lại giảm đến 50%. Phương pháp kiểm tra được thực hiện rất nghiêm ngặt: mỗi lần thử nghiệm đều bắt đầu khi pin ở mức 97%, chờ tự tụt xuống 96% rồi mới chạy game ở chế độ full tải trong 16 phút. Kết quả kiểm tra lặp lại 4 lần (2 lần full res, 2 lần half res) cho thấy sự chênh lệch tiêu thụ điện năng rõ rệt.

Ngoài ra, hệ thống hiệu ứng (dùng Effekseer) cũng là nguồn ngốn CPU đáng kể. Ban đầu các nghệ sĩ chỉ tập trung vào chất lượng hình ảnh mà chưa quan tâm đến hiệu năng. Chúng tôi đã di chuyển hệ thống này sang luồng xử lý độc lập, giúp giảm thời gian xử lý mỗi frame nhưng không cải thiện mức tiêu thụ năng lượng. Giải pháp tiếp theo là tạm dừng các particle emitter nằm ngoài tầm nhìn camera, dù điều này gây ra một số lỗi hình ảnh nhỏ nhưng chấp nhận được để đổi lấy hiệu suất.

Trong tương lai, ngoài tiếp tục tối ưu engine, chúng tôi sẽ tập trung vào tối ưu tài nguyên nghệ thuật: giảm kích thước texture, đơn giản hóa mô hình 3D, tối ưu animation. Hiện tại, engine của chúng tôi chủ yếu viết bằng Lua, chỉ chuyển đổi một số module trọng yếu sang C/C++ trong năm qua. Cách tiếp cận này kết hợp giữa tốc độ phát triển của Lua và hiệu suất của C/C++, đồng thời tận dụng tối đa lợi thế của mô hình đa luồng thông qua việc sử dụng nhiều máy ảo Lua song song.

0%