experimental optimize canvas:set_data using ffi

This commit is contained in:
MihailRis 2025-03-08 17:33:56 +03:00
parent 6078a8802e
commit e48216da40
6 changed files with 61 additions and 13 deletions

View File

@ -1,3 +1,31 @@
local _ffi = ffi
ffi = nil
-- Lua has no parallelizm, also _set_data does not call any lua functions so
-- may be reused one global ffi buffer per lua_State
local canvas_ffi_buffer
local canvas_ffi_buffer_size = 0
function __vc_Canvas_set_data(self, data)
if type(data) == "cdata" then
self:_set_data(tostring(_ffi.cast("uintptr_t", data)))
end
local width = self.width
local height = self.height
local size = width * height * 4
if size > canvas_ffi_buffer_size then
canvas_ffi_buffer = _ffi.new(
string.format("unsigned char[%s]", size)
)
canvas_ffi_buffer_size = size
end
for i=0, size - 1 do
canvas_ffi_buffer[i] = data[i + 1]
end
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)))
end
-- Check if given table is an array
function is_array(x)
if #x > 0 then

View File

@ -88,14 +88,17 @@ static void create_libs(State* L, StateType stateType) {
void lua::init_state(State* L, StateType stateType) {
// Allowed standard libraries
pop(L, luaopen_base(L));
pop(L, luaopen_math(L));
pop(L, luaopen_string(L));
pop(L, luaopen_table(L));
pop(L, luaopen_debug(L));
pop(L, luaopen_jit(L));
pop(L, luaopen_bit(L));
pop(L, luaopen_os(L));
luaL_openlibs(L);
if (getglobal(L, "require")) {
pushstring(L, "ffi");
if (call_nothrow(L, 1, 1)) {
setglobal(L, "ffi");
}
}
pushnil(L);
setglobal(L, "io");
const char* removed_os[] {
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
remove_lib_funcs(L, "os", removed_os);

View File

@ -163,20 +163,23 @@ int lua::call(State* L, int argc, int nresults) {
int handler_pos = gettop(L) - argc;
pushcfunction(L, l_error_handler);
insert(L, handler_pos);
int top = gettop(L);
if (lua_pcall(L, argc, nresults, handler_pos)) {
std::string log = tostring(L, -1);
pop(L);
remove(L, handler_pos);
throw luaerror(log);
}
int added = gettop(L) - (top - argc - 1);
remove(L, handler_pos);
return nresults == -1 ? 1 : nresults;
return added;
}
int lua::call_nothrow(State* L, int argc, int nresults) {
int handler_pos = gettop(L) - argc;
pushcfunction(L, l_error_handler);
insert(L, handler_pos);
int top = gettop(L);
if (lua_pcall(L, argc, -1, handler_pos)) {
auto errorstr = tostring(L, -1);
if (errorstr) {
@ -188,8 +191,9 @@ int lua::call_nothrow(State* L, int argc, int nresults) {
remove(L, handler_pos);
return 0;
}
int added = gettop(L) - (top - argc - 1);
remove(L, handler_pos);
return 1;
return added;
}
void lua::dump_stack(State* L) {

View File

@ -25,7 +25,8 @@ namespace lua {
if (n < 0) {
abort();
}
if (lua_gettop(L) < n) {
int top = lua_gettop(L);
if (top < n) {
abort();
}
#endif
@ -63,6 +64,9 @@ namespace lua {
inline void rawseti(lua::State* L, int n, int idx = -2) {
lua_rawseti(L, idx, n);
}
inline void rawset(lua::State* L, int idx = -3) {
lua_rawset(L, idx);
}
inline int createtable(lua::State* L, int narr, int nrec) {
lua_createtable(L, narr, nrec);

View File

@ -136,6 +136,12 @@ static int l_set_data(State* L) {
auto& canvas = require_canvas(L, 1);
auto& image = canvas.data();
auto data = image.getData();
if (lua::isstring(L, 2)) {
auto ptr = reinterpret_cast<ubyte*>(std::stoull(lua::tostring(L, 2)));
std::memcpy(data, ptr, image.getDataSize());
return 0;
}
int len = objlen(L, 2);
if (len < image.getDataSize()) {
throw std::runtime_error(
@ -167,7 +173,7 @@ static std::unordered_map<std::string, lua_CFunction> methods {
{"blit", lua::wrap<l_blit>},
{"clear", lua::wrap<l_clear>},
{"update", lua::wrap<l_update>},
{"set_data", lua::wrap<l_set_data>},
{"_set_data", lua::wrap<l_set_data>},
};
static int l_meta_index(State* L) {
@ -189,6 +195,9 @@ static int l_meta_index(State* L) {
if (!strcmp(name, "height")) {
return pushinteger(L, data.getHeight());
}
if (!strcmp(name, "set_data")) {
return getglobal(L, "__vc_Canvas_set_data");
}
if (auto func = methods.find(tostring(L, 2)); func != methods.end()) {
return pushcfunction(L, func->second);
}

View File

@ -120,7 +120,7 @@ std::unique_ptr<Process> scripting::start_coroutine(
lua::loadbuffer(L, 0, source, script.name());
if (lua::call(L, 1)) {
int id = lua::tointeger(L, -1);
lua::pop(L, 2);
lua::pop(L, 1);
return std::make_unique<LuaCoroutine>(L, id);
}
lua::pop(L);