Add patch and first version of mod

master
Pedro Gimeno 2019-04-27 00:51:19 +02:00
parent 49bc6f209c
commit 24f0146f0d
2 changed files with 430 additions and 0 deletions

151
ffi_accel.patch Normal file
View File

@ -0,0 +1,151 @@
commit bb973c7d07e6b901f86695935c6936adb24a393f
Author: Pedro Gimeno <pgimeno@users.noreply.notabug.org>
Date: Mon Apr 22 03:11:55 2019 +0200
Add FFI pointer and size retrieval and sanity check functions
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 9761a661..ce9e1bbd 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include <string>
#include <sstream>
+#include <cstddef>
static const Rotation wallmounted_to_rot[] = {
ROTATE_0, ROTATE_180, ROTATE_90, ROTATE_270
@@ -44,6 +45,18 @@ static const u8 rot_to_wallmounted[] = {
MapNode
*/
+#if USE_LUAJIT
+
+extern "C" int get_mapnode_version(void)
+{
+ if (sizeof(MapNode) == 4 && offsetof(MapNode, param0) == 0
+ && offsetof(MapNode, param1) == 2 && offsetof(MapNode, param2) == 3)
+ return 1;
+ return 0;
+}
+
+#endif
+
void MapNode::getColor(const ContentFeatures &f, video::SColor *color) const
{
if (f.palette) {
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index e38d319f..c1f2b710 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "config.h"
#include "lua_api/l_noise.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
@@ -401,6 +402,53 @@ luaL_Reg LuaPerlinNoiseMap::methods[] = {
{0,0}
};
+#if USE_LUAJIT
+
+extern "C" {
+
+size_t PerlinNoiseMap_get_area(void **pnmp)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ if (pnmp == nullptr)
+ throw ModError("Nil pointer in C call");
+
+ LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)pnmp;
+
+ Noise *n = o->getNoise();
+
+ return n->sx * n->sy;
+}
+
+size_t PerlinNoiseMap_get_volume(void **pnmp)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ if (pnmp == nullptr)
+ throw ModError("Nil pointer in C call");
+
+ LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)pnmp;
+
+ Noise *n = o->getNoise();
+
+ return n->sx * n->sy * n->sz;
+}
+
+void PerlinNoiseMap_get_pointer(void **pnmp, void **ptr)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ if (pnmp == nullptr || ptr == nullptr)
+ throw ModError("Nil pointer in C call");
+
+ LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)pnmp;
+ *ptr = o->getNoise();
+}
+
+} // extern "C"
+
+#endif // USE_LUAJIT
+
///////////////////////////////////////
/*
LuaPseudoRandom
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index 9f50dfd3..49a7ec6e 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -91,6 +91,8 @@ class LuaPerlinNoiseMap : public ModApiBase
static LuaPerlinNoiseMap *checkobject(lua_State *L, int narg);
static void Register(lua_State *L);
+
+ Noise *getNoise() const { return noise; }
};
/*
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index c92983bd..2a205ff2 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -30,6 +30,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen/mapgen.h"
#include "voxelalgorithms.h"
+#if USE_LUAJIT
+
+extern "C" {
+
+void VoxelManip_get_pointer(void **lvmp, void **ptr)
+{
+ if (lvmp == nullptr || ptr == nullptr)
+ throw ModError("Nil pointer in C call");
+
+ *ptr = (*(LuaVoxelManip **)lvmp)->vm->m_data;
+}
+
+s32 VoxelManip_get_volume(void **lvmp)
+{
+ if (lvmp == nullptr)
+ throw ModError("Nil pointer in C call");
+
+ return (*(LuaVoxelManip **)lvmp)->vm->m_area.getVolume();
+}
+
+} // extern "C"
+
+#endif
+
// garbage collector
int LuaVoxelManip::gc_object(lua_State *L)
{

279
init.lua Normal file
View File

@ -0,0 +1,279 @@
--[===================================================================[--
ffi_accel - Mod for Minetest to accelerate handling of LuaVoxelManip
and PerlinNoiseMap through the foreign function interface
Copyright © 2019 Pedro Gimeno Fortea. All rights reserved.
Permission is hereby granted to everyone to copy, modify, distribute
and use this file, for any purpose, in whole or in part, free of
charge, under the sole condition that the above copyright notice,
together with this permission grant and the disclaimer below, are
included in all copies of this software or of a substantial portion
of it.
THIS SOFTWARE COMES WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED.
--]===================================================================]--
-- Based on an idea of EvidenceBKidsCode.
-- This mod needs to apply a patch to the engine in order to work; see
--
local modname = "Mod ffi_accel"
local err_prefix = modname .. " won't have any effect because "
local ie = minetest.request_insecure_environment()
if not ie then
minetest.log("warning", err_prefix .. "it's not declared in secure.trusted_mods")
return
end
local ok, ffi = pcall(ie.require, 'ffi')
if not ok or not ffi then
minetest.log("warning", err_prefix .. "FFI is not available in this system")
return
end
ffi.cdef[[
typedef uint8_t u8;
typedef uint16_t u16;
typedef int32_t s32;
typedef struct {
u16 nodeid;
u8 light;
u8 param2;
} MapNode;
int get_mapnode_version(void);
void VoxelManip_get_pointer(void **lvmp, void **ptr);
s32 VoxelManip_get_volume(void **lvmp);
void PerlinNoiseMap_get_pointer(void **pnmp, void **ptr);
size_t PerlinNoiseMap_get_area(void **pnmp);
size_t PerlinNoiseMap_get_volume(void **pnmp);
]]
local ffiC = ffi.C
local ffinew = ffi.new
local VoidPtrPtr = ffi.typeof('void*[1]')
local MapNodePtr = ffi.typeof('MapNode *')
local mt_set_data, mt_set_light_data, mt_set_param2_data
if not pcall(function ()
assert(ffiC.get_mapnode_version and ffiC.VoxelManip_get_pointer
and ffiC.VoxelManip_get_volume and ffiC.PerlinNoiseMap_get_pointer)
end)
then
minetest.log("warning", err_prefix .. "your Minetest executable has not been patched to support FFI")
return
end
if ffiC.get_mapnode_version() ~= 1 then
minetest.log("warning", err_prefix .. "of incompatible map node structure")
return
end
-- Table of pointers (keys are weak refs)
local ptrtable = setmetatable({}, {__mode = 'k'})
-- Table of sizes (keys are weak refs)
local sizetable = setmetatable({}, {__mode = 'k'})
-- Metamethod: get a value
local function mm_get(t, idx)
return idx >= 1 and idx <= sizetable[t] and ptrtable[t][idx - 1] or rawget(t, idx)
end
-- Metamethod: set a value
local function mm_set(t, idx, value)
if idx >= 1 and idx <= sizetable[t] then
ptrtable[t][idx - 1] = value
else
rawset(t, idx, value)
end
end
-- Metamethod: get the nodeid of an index
local function mm_get_nodeid(t, idx)
return idx >= 1 and idx <= sizetable[t] and ptrtable[t][idx - 1].nodeid or rawget(t, idx)
end
-- Metamethod: set the nodeid of an index to a value
local function mm_set_nodeid(t, idx, value)
if idx >= 1 and idx <= sizetable[t] then
ptrtable[t][idx - 1].nodeid = value
else
rawset(t, idx, value)
end
end
-- Metamethod: get the light of an index
local function mm_get_light(t, idx)
return idx >= 1 and idx <= sizetable[t] and ptrtable[t][idx - 1].light or rawget(t, idx)
end
-- Metamethod: set the light of an index to a value
local function mm_set_light(t, idx, value)
if idx >= 1 and idx <= sizetable[t] then
ptrtable[t][idx - 1].light = value
else
rawset(t, idx, value)
end
end
-- Metamethod: get the param2 of an index
local function mm_get_param2(t, idx)
return idx >= 1 and idx <= sizetable[t] and ptrtable[t][idx - 1].param2 or rawget(t, idx)
end
-- Metamethod: set the param2 of an index to a value
local function mm_set_param2(t, idx, value)
if idx >= 1 and idx <= sizetable[t] then
ptrtable[t][idx - 1].param2 = value
else
rawset(t, idx, value)
end
end
-- Metatables for VoxelManip nodeid, light and param2
local VoxelManip_nodeid_mt = { __index = mm_get_nodeid, __newindex = mm_set_nodeid }
local VoxelManip_light_mt = { __index = mm_get_light, __newindex = mm_set_light }
local VoxelManip_param2_mt = { __index = mm_get_param2, __newindex = mm_set_param2 }
-- Replacement VoxelManip.get_data and VoxelManip.set_data methods
local function VoxelManip_get_data(self, buffer)
-- Set up the metatable and pointer
buffer = setmetatable(buffer or {}, VoxelManip_nodeid_mt)
do
local ptr = VoidPtrPtr()
ffiC.VoxelManip_get_pointer(self, ptr)
ptrtable[buffer] = MapNodePtr(ptr[0])
end
sizetable[buffer] = ffiC.VoxelManip_get_volume(self)
return buffer
end
local function VoxelManip_set_data(self, buffer)
-- Call the original set_data method if the metatable is not
-- the one we've set
if getmetatable(buffer) ~= VoxelManip_nodeid_mt then
mt_set_data(self, buffer)
end
end
-- Replacement VoxelManip.get/set_light_data methods
local function VoxelManip_get_light_data(self, buffer)
-- Set up the metatable and pointer
buffer = setmetatable(buffer or {}, VoxelManip_light_mt)
do
local ptr = VoidPtrPtr()
ffiC.VoxelManip_get_pointer(self, ptr)
ptrtable[buffer] = MapNodePtr(ptr[0])
end
sizetable[buffer] = ffiC.VoxelManip_get_volume(self)
return buffer
end
local function VoxelManip_set_light_data(self, buffer)
-- Call the original set_light_data method if the metatable is not
-- the one we've set
if getmetatable(buffer) ~= VoxelManip_light_mt then
mt_set_light_data(self, buffer)
end
end
-- Replacement VoxelManip.get/set_param2_data methods
local function VoxelManip_get_param2_data(self, buffer)
-- Set up the metatable and pointer
buffer = setmetatable(buffer or {}, VoxelManip_param2_mt)
do
local ptr = VoidPtrPtr()
ffiC.VoxelManip_get_pointer(self, ptr)
ptrtable[buffer] = MapNodePtr(ptr[0])
end
sizetable[buffer] = ffiC.VoxelManip_get_volume(self)
return buffer
end
local function VoxelManip_set_param2_data(self, buffer)
-- Call the original set_param2_data method if the metatable is not
-- the one we've set
if getmetatable(buffer) ~= VoxelManip_param2_mt then
mt_set_param2_data(self, buffer)
end
end
-- Metatable for PerlinNoiseMap
local PerlinNoiseMap_mt = { __index = mm_get }
-- Replacement methods for PerlinNoiseMap.*
local function PerlinNoiseMap_get_2d_map_flat(self, pos, buffer)
-- Calculate the noise
self:calc_2d_map(pos)
-- Prepare the metatable for direct access to the data
buffer = setmetatable(buffer or {}, PerlinNoiseMap_mt)
do
local ptr = VoidPtrPtr()
ffiC.PerlinNoiseMap_get_pointer(self, ptr)
ptrtable[buffer] = MapNodePtr(ptr[0])
end
sizetable[buffer] = ffiC.PerlinNoiseMap_get_area(self)
return buffer
end
local function PerlinNoiseMap_get_3d_map_flat(self, pos, buffer)
-- Calculate the noise
self:calc_3d_map(pos)
-- Prepare the metatable for direct access to the data
buffer = setmetatable(buffer or {}, PerlinNoiseMap_mt)
do
local ptr = VoidPtrPtr()
ffiC.PerlinNoiseMap_get_pointer(self, ptr)
ptrtable[buffer] = MapNodePtr(ptr[0])
end
sizetable[buffer] = ffiC.PerlinNoiseMap_get_volume(self)
return buffer
end
--[[
local function PerlinNoiseMap_get_map_slice(slice_offset, slice_size, buffer)
-- TODO
end
--]]
-- Monkey-patch VoxelManip and PerlinNoiseMap
minetest.after(0, function()
-- VoxelManip buffer-intensive methods
local mt = getmetatable(minetest.get_voxel_manip())
mt.get_data = VoxelManip_get_data
mt_set_data = mt.set_data
mt.set_data = VoxelManip_set_data
mt.get_light_data = VoxelManip_get_light_data
mt_set_light_data = mt.set_light_data
mt.set_light_data = VoxelManip_set_light_data
mt.get_param2_data = VoxelManip_get_param2_data
mt_set_param2_data = mt.set_param2_data
mt.set_param2_data = VoxelManip_set_param2_data
-- PerlinNoiseMap buffer-intensive methods
mt = getmetatable(minetest.get_perlin_map({spread = {x=100, y=100, z=100}}, {x=1, y=1, z=1}))
mt.get_2d_map_flat = PerlinNoiseMap_get_2d_map_flat
mt.get_3d_map_flat = PerlinNoiseMap_get_3d_map_flat
-- mt.get_map_slice = PerlinNoiseMap_get_map_slice
-- Aliases
mt.get2DMap_flat = mt.get_2d_map_flat
mt.get3DMap_flat = mt.get_3d_map_flat
-- mt.getMapSlice = mt.get_map_slice
end)
minetest.log("action", modname .. " activated!")