zoukankan      html  css  js  c++  java
  • Xlua对c#的vector3等结构体的优化

    参考文章::
    一、lua如何操作Vector3,中间做了什么操作?
    1.获取Vector3对象
    由于Vector3的方法、属性都是成员方法、属性(如x、y、z、Slerp),那么调用这些方法前需要先获取Vector3对应的对象。比如Vector3()新建、transform.position获取等。
    以transform.position为例:_g_get_position方法创建了一个CSharpStruct类型的ud,并把x,y,z存在这个ud里。这个ud的元表指向Vector3的obj_meta,通过这个元表可以访问Vector3Wrap注册的所有方法、属性,进而间接访问到Vector3。
    ud = 
    {
        ["fake_id"] = -1
        ["len"] = 12 //存储3个float值的大小,的对应xyz,float是4字节32位。
        ["data"][0] = x
        ["data"][1] = y
        ["data"][0] = z
        ["__index"] = obj_meta
    }
    static int _g_get_position(RealStatePtr L)
    {
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
     
            UnityEngine.Transform gen_to_be_invoked = (UnityEngine.Transform)translator.FastGetCSObj(L, 1);
            translator.PushUnityEngineVector3(L, gen_to_be_invoked.position);
        } catch(System.Exception gen_e) {
            return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
        }
        return 1;
    }
     
    public void PushUnityEngineVector3(RealStatePtr L, UnityEngine.Vector3 val)
    {
        if (UnityEngineVector3_TypeID == -1)
        {
            bool is_first;
            UnityEngineVector3_TypeID = getTypeId(L, typeof(UnityEngine.Vector3), out is_first);   
        }
        //创建一个大小为(12+4+4)字节的userdata,元表Vector3的元表
        IntPtr buff = LuaAPI.xlua_pushstruct(L, 12, UnityEngineVector3_TypeID);
        if (!CopyByValue.Pack(buff, 0, val)) //把vector3拆成3个float传入cc,在c的结构体buff存储数据
        {
        throw new Exception("pack fail fail for UnityEngine.Vector3 ,value="+val);
        }
    }
    xlua.c里的接口:
    LUA_API void *xlua_pushstruct(lua_State *L, unsigned int size, int meta_ref) {
       CSharpStruct *css = (CSharpStruct *)lua_newuserdata(L, size + sizeof(int) + sizeof(unsigned int));
       css->fake_id = -1;
       css->len = size;
        lua_rawgeti(L, LUA_REGISTRYINDEX, meta_ref);
       lua_setmetatable(L, -2);
       return css;
    }
     
    LUALIB_API int xlua_pack_float3(void *p, int offset, float f1, float f2, float f3) {
       CSharpStruct *css = (CSharpStruct *)p;
       if (css->fake_id != -1 || css->len < offset + sizeof(float) * 3) {
          return 0;
       } else {
          float *pos = (float *)(&(css->data[0]) + offset);
          pos[0] = f1;
          pos[1] = f2;
          pos[2] = f3;
          return 1;
       }
    }
    2.设置transform.position
    代码如下:
    主要是UnPack方法调用xlua的xlua_unpack_float3方法,从上面的ud结构里取到x,y,c的值压栈并赋值给UnPack的x,y,z参数,再由UnPack组装一个新的Vevtor3返回给_s_set_position进行赋值。
    static int _s_set_position(RealStatePtr L)
    {
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
     
            UnityEngine.Transform gen_to_be_invoked = (UnityEngine.Transform)translator.FastGetCSObj(L, 1);
            UnityEngine.Vector3 gen_value;
            translator.Get(L, 2, out gen_value);
            gen_to_be_invoked.position = gen_value;      
        } catch(System.Exception gen_e) {
            return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
        }
        return 0;
    }
     
    public void Get(RealStatePtr L, int index, out UnityEngine.Vector3 val)
    {
        LuaTypes type = LuaAPI.lua_type(L, index);
        if (type == LuaTypes.LUA_TUSERDATA )
        {
            IntPtr buff = LuaAPI.lua_touserdata(L, index);
            if (!CopyByValue.UnPack(buff, 0, out val))
            {
                throw new Exception("unpack fail for UnityEngine.Vector3");
            }
        }
        else if (type ==LuaTypes.LUA_TTABLE)
        {
            CopyByValue.UnPack(this, L, index, out val);
        }
        else
        {
            val = (UnityEngine.Vector3)objectCasters.GetCaster(typeof(UnityEngine.Vector3))(L, index, null);
        }
    }
     
    public static bool UnPack(IntPtr buff, int offset, out UnityEngine.Vector3 field)
    {
        field = default(UnityEngine.Vector3);
        
        float x = default(float);
        float y = default(float);
        float z = default(float);
        
        if(!LuaAPI.xlua_unpack_float3(buff, offset, out x, out y, out z))
        {
            return false;
        }
        field.x = x;
        field.y = y;
        field.z = z;
        
        
        return true;
    }
    当然,如果你传的不是Vector3类型的usreData就更简单了,例如{x = 1, y = 2, z = 3},直接调用lua_rawget就可以取到了。
    public static void UnPack(ObjectTranslator translator, RealStatePtr L, int idx, out UnityEngine.Vector3 val)
    {
        val = new UnityEngine.Vector3();
              int top = LuaAPI.lua_gettop(L);
       
       if (Utils.LoadField(L, idx, "x"))
              {
           
                  translator.Get(L, top + 1, out val.x);
          
              }
              LuaAPI.lua_pop(L, 1);
       
       if (Utils.LoadField(L, idx, "y"))
              {
           
                  translator.Get(L, top + 1, out val.y);
          
              }
              LuaAPI.lua_pop(L, 1);
       
       if (Utils.LoadField(L, idx, "z"))
              {
           
                  translator.Get(L, top + 1, out val.z);
          
              }
              LuaAPI.lua_pop(L, 1);
       
    }
     
    public static bool LoadField(RealStatePtr L, int idx, string field_name)
    {
       idx = idx > 0 ? idx : LuaAPI.lua_gettop(L) + idx + 1;// abs of index
       LuaAPI.xlua_pushasciistring(L, field_name);
       LuaAPI.lua_rawget(L, idx);
       return !LuaAPI.lua_isnil(L, -1);
    }
    xlua.c的解包方法:
    LUALIB_API int xlua_unpack_float3(void *p, int offset, float *f1, float *f2, float *f3) {
       CSharpStruct *css = (CSharpStruct *)p;
       if (css->fake_id != -1 || css->len < offset + sizeof(float) * 3) {
          return 0;
       } else {
          float *pos = (float *)(&(css->data[0]) + offset);
          *f1 = pos[0];
          *f2 = pos[1];
          *f3 = pos[2];
          return 1;
       }
    }
    3.Vector.x:取x值
    流程其实跟transform.position差不多,先把自身的ud转成Vector3,再把Vector3.x压栈返回给lua。
    static int _g_get_x(RealStatePtr L)
    {
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
     
            UnityEngine.Vector3 gen_to_be_invoked;
            translator.Get(L, 1, out gen_to_be_invoked);
            LuaAPI.lua_pushnumber(L, gen_to_be_invoked.x);
        } catch(System.Exception gen_e) {
            return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
        }
        return 1;
    }
    4.调用总结:
    lua跟c#的Vector3并没有直接的调用,而是通过中间层ud(CSharpStruct)进行中转。
    这里面的PushUnityEngineVector3、Get方法都是在wrap生成时动态生成的。
    每个GCOptimize标记的方法都会生成对应的Push、Get、Pack、UnPack方法,这些方法会调用到xlua.c里对应的c方法对结构体进行解包、封包。
    二、xlua为什么要这么做?
    Vector3Wrap的__CreateInstance方法使用的是translator.PushUnityEngineVector3对Vector对象压栈。那为什么不用正常的translator.Push压栈呢?
    static int __CreateInstance(RealStatePtr L)
    {        
        try {
            ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
            if(LuaAPI.lua_gettop(L) == 4 && LuaTypes.LUA_TNUMBER == LuaAPI.lua_type(L, 2) && LuaTypes.LUA_TNUMBER == LuaAPI.lua_type(L, 3) && LuaTypes.LUA_TNUMBER == LuaAPI.lua_type(L, 4))
            {
                float _x = (float)LuaAPI.lua_tonumber(L, 2);
                float _y = (float)LuaAPI.lua_tonumber(L, 3);
                float _z = (float)LuaAPI.lua_tonumber(L, 4);
          
                UnityEngine.Vector3 gen_ret = new UnityEngine.Vector3(_x, _y, _z);
                translator.PushUnityEngineVector3(L, gen_ret);
                     
                return 1;
            }
        }
        catch(System.Exception gen_e) {
           return LuaAPI.luaL_error(L, "c# exception:" + gen_e);
        }        
    }
    translator.Push里会调用addObject把对象实例跟对象下标做一个绑定,这个唯一的下标用于在lua中获取到c#的对象实例。Struct是值类型,值类型和引用类型(object)的转换会涉及装箱、拆箱操作。
    int addObject(object obj, bool is_valuetype, bool is_enum)
    {
              int index = objects.Add(obj);
              if (is_enum)
              {
                  enumMap[obj] = index;
              }
              else if (!is_valuetype)
              {
                  reverseMap[obj] = index;
              }
       
       return index;
    }
    对装箱、拆箱不了解的可以参考文章:https://www.cnblogs.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html
     
    所以xlua其实是对Vector3等值类型的结构体做了一个优化,避免了装箱和拆箱优化
    但是,虽然xlua对结构体做了优化,但还是会有很多开销,例如:在c#需要push xyz参数,在lua需要创建表保存xyz值,需要查询元表等。
     
    那么如何优化呢?直接在函数中传递三个float,要比传递Vector3要更快。
    例如void SetPos(GameObject obj, Vector3pos)改为void SetPos(GameObject obj, float x, floaty, float z)。
    对于c#的Struct还是少用,尽量封装静态方法调用,性能会更好。
  • 相关阅读:
    PHP 5.5.0 Alpha5 发布
    Ubuntu Touch 只是另一个 Android 皮肤?
    MariaDB 10 已经为动态列提供文档说明
    Percona Toolkit 2.1.9 发布,MySQL 管理工具
    Oracle Linux 6.4 发布
    Ruby 2.0.0 首个稳定版本(p0)发布
    Apache Pig 0.11.0 发布,大规模数据分析
    Node.js 0.8.21 稳定版发布
    红薯 MySQL 5.5 和 5.6 默认参数值的差异
    Django 1.5 正式版发布,支持 Python 3
  • 原文地址:https://www.cnblogs.com/wang-jin-fu/p/13508789.html
Copyright © 2011-2022 走看看