Phương Pháp Truyền Thông Tin Đến Máy Ảo Lua - nói dối e blog

Phương Pháp Truyền Thông Tin Đến Máy Ảo Lua

Khi logic chương trình được chuyển giao cho script xử lý, tầng C/C++ lúc này chỉ cần tập trung vào việc truyền tải các thông tin đầu vào thiết yếu vào máy ảo. Tuy nhiên, việc tối ưu hóa hiệu suất truyền tải vẫn là một yêu cầu quan trọng.

Lấy ví dụ cụ thể về việc truyền tọa độ chuột đến máy ảo Lua, một phương pháp quen thuộc là định nghĩa hàm C get_mouse_pos. Khi script Lua cần lấy tọa độ chuột, nó sẽ gọi hàm này. Tuy nhiên, cách tiếp cận này tồn tại điểm hạn chế: mỗi lần truy vấn tọa độ chuột đều phải thực hiện chuyển đổi giữa máy ảo và mã native, gây tiêu hao tài nguyên.

Một giải pháp tối ưu hơn là: cho phép script chỉ gọi get_mouse_pos duy nhất một lần, sau đó lưu trữ dữ liệu vào biến toàn cục. Trong suốt quá trình thực thi một frame, thay vì gọi hàm liên tục, script sẽ truy cập trực tiếp các biến toàn cục để lấy vị trí chuột.

Phát triển ý tưởng này, chúng ta có thể chủ động cập nhật biến toàn cục từ phía C. Sau khi xử lý tin nhắn Windows trong mã native, thông tin chuột sẽ được đẩy trực tiếp vào máy ảo Lua bằng đoạn mã sau:

1
2
3
4
5
6
7
lua_pushstring(L, "MOUSE_X"); 
lua_pushnumber(L, mouse_x); 
lua_settable(L, LUA_GLOBALSINDEX);

lua_pushstring(L, "MOUSE_Y"); 
lua_pushnumber(L, mouse_y); 
lua_settable(L, LUA_GLOBALSINDEX);

Tuy nhiên, thao tác lua_pushstring vẫn gây ra vấn đề hiệu suất. Mỗi lần gọi, Lua phải kiểm tra sự tồn tại của chuỗi trong máy ảo để tránh trùng lặp. Dù MOUSE_XMOUSE_Y đã tồn tại từ lần chạy đầu tiên, quá trình so sánh chuỗi vẫn tiêu tốn thời gian. Để tối ưu, chúng ta có thể tiền xử lý như sau:

1
2
3
4
5
6
// Tiền tạo chuỗi và lưu tham chiếu
lua_pushstring(L, "MOUSE_X"); 
_mouse_x_ref = lua_ref(L, -1);

lua_pushstring(L, "MOUSE_Y"); 
_mouse_y_ref = lua_ref(L, -1);

Sau đó, khi cập nhật tọa độ chuột chỉ cần dùng lua_getref - thao tác nhanh hơn đáng kể nhờ cơ chế tối ưu của Lua với bảng băm khóa số:

1
2
3
4
5
6
7
lua_getref(L, _mouse_x_ref); 
lua_pushnumber(L, mouse_x); 
lua_settable(L, LUA_GLOBALSINDEX);

lua_getref(L, _mouse_y_ref); 
lua_pushnumber(L, mouse_y); 
lua_settable(L, LUA_GLOBALSINDEX);

Tiếp tục nâng cấp giải pháp, chúng ta có thể tạo file mouse.lua chứa hàm Lua chuyên trách:

1
2
3
return function(mx, my) 
    MOUSE_X, MOUSE_Y = mx, my 
end

Trong quá trình khởi động:

1
2
lua_dofile(L, "mouse.lua"); 
_mouse_set_ref = lua_ref(L, -1);

Khi cần cập nhật tọa độ:

1
2
3
4
lua_getref(L, _mouse_set_ref); 
lua_pushnumber(L, mouse_x); 
lua_pushnumber(L, mouse_y); 
lua_call(L, 2, 0);

Phương pháp này chỉ cần duy trì một tham chiếu hàm, đồng thời tận dụng các lệnh giả (pseudo-instruction) của máy ảo để xử lý dữ liệu. Dù lua_call có chi phí cố định, giải pháp này lại thể hiện tính linh hoạt vượt trội khi cần truyền tải nhiều thông tin phức tạp từ mã native sang script.

Lưu ý: Mọi tham chiếu tạo bởi lua_ref đều cần được giải phóng bằng lua_unref khi không còn sử dụng để tránh rò rỉ bộ nhớ.

0%