experimental optimize canvas:set_data using ffi
This commit is contained in:
@@ -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
|
-- Check if given table is an array
|
||||||
function is_array(x)
|
function is_array(x)
|
||||||
if #x > 0 then
|
if #x > 0 then
|
||||||
|
|||||||
@@ -88,14 +88,17 @@ static void create_libs(State* L, StateType stateType) {
|
|||||||
|
|
||||||
void lua::init_state(State* L, StateType stateType) {
|
void lua::init_state(State* L, StateType stateType) {
|
||||||
// Allowed standard libraries
|
// Allowed standard libraries
|
||||||
pop(L, luaopen_base(L));
|
luaL_openlibs(L);
|
||||||
pop(L, luaopen_math(L));
|
|
||||||
pop(L, luaopen_string(L));
|
if (getglobal(L, "require")) {
|
||||||
pop(L, luaopen_table(L));
|
pushstring(L, "ffi");
|
||||||
pop(L, luaopen_debug(L));
|
if (call_nothrow(L, 1, 1)) {
|
||||||
pop(L, luaopen_jit(L));
|
setglobal(L, "ffi");
|
||||||
pop(L, luaopen_bit(L));
|
}
|
||||||
pop(L, luaopen_os(L));
|
}
|
||||||
|
pushnil(L);
|
||||||
|
setglobal(L, "io");
|
||||||
|
|
||||||
const char* removed_os[] {
|
const char* removed_os[] {
|
||||||
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
|
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
|
||||||
remove_lib_funcs(L, "os", removed_os);
|
remove_lib_funcs(L, "os", removed_os);
|
||||||
|
|||||||
@@ -163,20 +163,23 @@ int lua::call(State* L, int argc, int nresults) {
|
|||||||
int handler_pos = gettop(L) - argc;
|
int handler_pos = gettop(L) - argc;
|
||||||
pushcfunction(L, l_error_handler);
|
pushcfunction(L, l_error_handler);
|
||||||
insert(L, handler_pos);
|
insert(L, handler_pos);
|
||||||
|
int top = gettop(L);
|
||||||
if (lua_pcall(L, argc, nresults, handler_pos)) {
|
if (lua_pcall(L, argc, nresults, handler_pos)) {
|
||||||
std::string log = tostring(L, -1);
|
std::string log = tostring(L, -1);
|
||||||
pop(L);
|
pop(L);
|
||||||
remove(L, handler_pos);
|
remove(L, handler_pos);
|
||||||
throw luaerror(log);
|
throw luaerror(log);
|
||||||
}
|
}
|
||||||
|
int added = gettop(L) - (top - argc - 1);
|
||||||
remove(L, handler_pos);
|
remove(L, handler_pos);
|
||||||
return nresults == -1 ? 1 : nresults;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua::call_nothrow(State* L, int argc, int nresults) {
|
int lua::call_nothrow(State* L, int argc, int nresults) {
|
||||||
int handler_pos = gettop(L) - argc;
|
int handler_pos = gettop(L) - argc;
|
||||||
pushcfunction(L, l_error_handler);
|
pushcfunction(L, l_error_handler);
|
||||||
insert(L, handler_pos);
|
insert(L, handler_pos);
|
||||||
|
int top = gettop(L);
|
||||||
if (lua_pcall(L, argc, -1, handler_pos)) {
|
if (lua_pcall(L, argc, -1, handler_pos)) {
|
||||||
auto errorstr = tostring(L, -1);
|
auto errorstr = tostring(L, -1);
|
||||||
if (errorstr) {
|
if (errorstr) {
|
||||||
@@ -188,8 +191,9 @@ int lua::call_nothrow(State* L, int argc, int nresults) {
|
|||||||
remove(L, handler_pos);
|
remove(L, handler_pos);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int added = gettop(L) - (top - argc - 1);
|
||||||
remove(L, handler_pos);
|
remove(L, handler_pos);
|
||||||
return 1;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua::dump_stack(State* L) {
|
void lua::dump_stack(State* L) {
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ namespace lua {
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
if (lua_gettop(L) < n) {
|
int top = lua_gettop(L);
|
||||||
|
if (top < n) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -63,6 +64,9 @@ namespace lua {
|
|||||||
inline void rawseti(lua::State* L, int n, int idx = -2) {
|
inline void rawseti(lua::State* L, int n, int idx = -2) {
|
||||||
lua_rawseti(L, idx, n);
|
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) {
|
inline int createtable(lua::State* L, int narr, int nrec) {
|
||||||
lua_createtable(L, narr, nrec);
|
lua_createtable(L, narr, nrec);
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ static int l_set_data(State* L) {
|
|||||||
auto& canvas = require_canvas(L, 1);
|
auto& canvas = require_canvas(L, 1);
|
||||||
auto& image = canvas.data();
|
auto& image = canvas.data();
|
||||||
auto data = image.getData();
|
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);
|
int len = objlen(L, 2);
|
||||||
if (len < image.getDataSize()) {
|
if (len < image.getDataSize()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
@@ -167,7 +173,7 @@ static std::unordered_map<std::string, lua_CFunction> methods {
|
|||||||
{"blit", lua::wrap<l_blit>},
|
{"blit", lua::wrap<l_blit>},
|
||||||
{"clear", lua::wrap<l_clear>},
|
{"clear", lua::wrap<l_clear>},
|
||||||
{"update", lua::wrap<l_update>},
|
{"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) {
|
static int l_meta_index(State* L) {
|
||||||
@@ -189,6 +195,9 @@ static int l_meta_index(State* L) {
|
|||||||
if (!strcmp(name, "height")) {
|
if (!strcmp(name, "height")) {
|
||||||
return pushinteger(L, data.getHeight());
|
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()) {
|
if (auto func = methods.find(tostring(L, 2)); func != methods.end()) {
|
||||||
return pushcfunction(L, func->second);
|
return pushcfunction(L, func->second);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ std::unique_ptr<Process> scripting::start_coroutine(
|
|||||||
lua::loadbuffer(L, 0, source, script.name());
|
lua::loadbuffer(L, 0, source, script.name());
|
||||||
if (lua::call(L, 1)) {
|
if (lua::call(L, 1)) {
|
||||||
int id = lua::tointeger(L, -1);
|
int id = lua::tointeger(L, -1);
|
||||||
lua::pop(L, 2);
|
lua::pop(L, 1);
|
||||||
return std::make_unique<LuaCoroutine>(L, id);
|
return std::make_unique<LuaCoroutine>(L, id);
|
||||||
}
|
}
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
|
|||||||
Reference in New Issue
Block a user