Kế Hoạch Cải Tiến Mô-Đun Shader Ejoy2d - nói dối e blog

Kế Hoạch Cải Tiến Mô-Đun Shader Ejoy2d

Với sự tham gia phát triển rộng rãi từ nhiều kỹ sư trong công ty, dự án ejoy2d đã được chuyển về tên miền github chính thức của ejoy. Trong bối cảnh ứng dụng đa dạng cho nhiều dự án khác nhau, kiến trúc ban đầu của ejoy2d bắt đầu bộc lộ những điểm hạn chế quan trọng. Mỗi dự án thường điều chỉnh sâu vào phần shader nền tảng để đáp ứng các yêu cầu đặc thù như tối ưu hiệu năng cho trường hợp cụ thể hoặc triển khai hiệu ứng thị giác phức tạp. Thiết kế ban đầu đơn giản hóa mô-đun shader vì chỉ tập trung vào mục đích phát triển game 2D, dẫn đến các vấn đề như: bố cục attribute cố định, hệ thống quản lý uniform thiếu tính mở rộng.

Trên kiến trúc GPU di động hiện đại, xét từ góc độ API kết xuất, sự khác biệt giữa 2D và 3D thực chất không lớn - cả hai đều dựa trên cơ chế kết xuất tam giác. Cả hai cùng yêu cầu truyền dữ liệu đỉnh lên GPU xử lý qua vertex shader, sau đó tiến hành kết xuất pixel bằng fragment shader. Điểm khác biệt nằm ở quy mô xử lý: Engine 2D thường xử lý các phép biến đổi đơn giản không dùng đến projection/view matrix, tập trung vào quản lý lượng lớn các đối tượng tứ giác. Kỹ thuật tối ưu phổ biến là gộp nhiều tứ giác vào cùng một batch kết xuất, do đó việc tính toán world matrix (chủ yếu là tịnh tiến) thường được xử lý trên CPU trước khi gửi đến GPU.

Về bản chất, engine 2D là hệ thống xử lý hàng loạt các hình ảnh. Điều này đòi hỏi fragment shader cần linh hoạt đáp ứng nhiều kiểu biến đổi hình ảnh phức tạp, đồng thời tối ưu việc sử dụng texture thông qua các kỹ thuật đặc biệt thay vì triển khai hệ thống chiếu sáng phức tạp như engine 3D. Triết lý thiết kế ban đầu của ejoy2d nhấn mạnh vào việc đơn giản hóa mô hình GPU dựa trên đặc thù nghiệp vụ 2D, xây dựng framework bằng mã nguồn tối giản. Tôi luôn tin rằng sự đơn giản sẽ trực tiếp mang lại hiệu năng vượt trội, do đó nhiều thành phần shader bị “cứng hóa” (hardcode) với giao diện bên ngoài cực kỳ hạn chế để tối ưu tốc độ xử lý.

Quá trình phát triển trải qua ba dự án thực tế với sự đóng góp trực tiếp từ hơn chục thành viên đã giúp nhìn rõ những điểm yếu trong thiết kế hiện tại. Trong khi tôi tập trung vào skynet, các đồng nghiệp đã phải vá khẩn cấp nhiều điểm trên ejoy2d để giải quyết vấn đề thực tế. Điều này khiến tôi nhận ra cần xây dựng một hệ thống shader底层 linh hoạt hơn, đủ sức mở rộng để tiếp nhận các yếu tố engine 3D tương lai mà không làm tăng đáng kể độ phức tạp.

Trong hai tháng qua, tôi đã nghiên cứu sâu mã nguồn renderer của Unreal4, horde3d và pixellight. Lý do chọn tự phát triển thay vì dùng engine sẵn có gồm năm điểm chính:

  1. Quá trình giải quyết vấn đề bằng việc tự viết mã là trải nghiệm trí tuệ cực kỳ hấp dẫn.
  2. Nhiều engine lâu đời mang theo gánh nặng lịch sử - hỗ trợ các tính năng đã lỗi thời hoặc chạy theo nhiều API đồ họa khác nhau, điều không cần thiết cho thiết bị di động.
  3. Đặc tính GPU di động tương đối đồng nhất. Các tính năng chuyên sâu chỉ có trên PC/console khó phổ biến trong 3 năm tới, khiến việc tích hợp trở nên không cần thiết.
  4. Chỉ cần xây dựng phần nền tảng kết xuất cốt lõi, không cần hệ sinh thái công cụ, khối lượng công việc cho cả engine 2D/3D chỉ khoảng 15-30 ngày làm việc chuyên sâu.
  5. Không còn muốn phụ thuộc vào chính sách mã nguồn đóng của Unity3D (đặc biệt là hệ thống quản lý tài nguyên), cần tạo thêm lựa chọn khi dự án tương lai đòi hỏi yếu tố 3D.

Trong số các engine tham khảo, tôi đặc biệt ấn tượng với horde3d nhờ thiết kế tối giản. Chỉ cần đọc hiểu module RendererBase là nắm bắt toàn bộ cơ chế. Hệ thống chỉ tập trung đóng gói pipeline có thể lập trình của OpenGL, không tạo ra các lớp trừu tượng hào nhoáng không cần thiết. Trên nền RendererBase, hệ thống thiết kế thêm tầng Renderer phục vụ các yêu cầu cụ thể của engine 3D.

Mô-đun RendererBase tập trung vào: quản lý các trạng thái kết xuất, tạo shader, trừu tượng hóa attribute layout cùng vertex buffer. Các thành phần như texture và render target cũng được封装 ở tầng này. Horde3d xuất sắc trong việc dùng ID riêng quản lý tài nguyên, che giấu hoàn toàn ID cấp OpenGL/DirectX.

Trên thiết bị di động, hiện chưa cần thiết hỗ trợ MRT (multiple render target) vì kỹ thuật Deferred Shading chưa thực dụng. Dựa trên triết lý horde3d, cuối tuần qua tôi đã viết lại mô-đun shader với chưa đầy 2000 dòng mã, bao gồm thư viện C và wrapper Lua. Giao diện C chỉ định nghĩa dưới 30 API, đơn giản hơn nhiều so với 70+ API của RendererBase horde3d hay 150+ RHI của Unreal4. Phần wrapper Lua giúp kiểm thử nhanh trực tiếp từ script.

Dự án hiện đang được lưu trữ trong kho mã riêng tư trên github chờ hoàn thiện các chức năng cốt lõi.

0%