QML 的底层实现之 JavaScript 变量编码



  • QML 是基于 ECMA-262(JavaScript),通过 Qt 的机制进行拓展的高级编程语言。下面会简单讲讲 JavaScript 变量是如何在 C++ 中定义的。

    先看如下一段话:

    We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.

    In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double NaN (actually -qNaN)
    is indicated by a number that has the top 13 bits set. The other values are usually set to 0 by the
    processor, and are thus free for us to store other data. We keep pointers in there for managed objects,
    and encode the other types using the free space given to use by the unused bits for NaN values. This also
    works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory.

    On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that
    will make the number a NaN. The Masks below are used for encoding the other types.

    On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will get encoded
    with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These
    can be used, as the highest valid pointer on a 64 bit system is 2^48-1.

    If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer.
    This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set).

    Bit 15-17 is then used to encode other immediates.

    大意如下:

    使用两种不同的方式对 JS 值进行编码,一种是 32 位,一种是 64 位。

    在这两种情况下,使用 8 字节(int64)保存一个值或者一个包装了非数字变量的变体。使用前 13 个 bit 来标定 -qNaN,其他位一般置为零以便使用。在后 51 位中可以保存被管理对象的指针或者其他值,这是适用 64 位操作系统,因为现有的 64 位操作系统,一般只是用 48 位(2^48-1)进行寻址,这意味着有多余的 16 位( 2^16+1 )是不会被使用的。

    在 32 位系统上,直接将双精度浮点数进行保存。高 32 位配合位遮罩保存不同的非数字变量,例如 int 和指针。

    在 64 位上,通过 0xffff8000 << 32 这个位遮罩存取浮点数,这样的效果是,不直接对双精度进行编码,最高的 13 位直接置为零。现在可以使用 14~17 位对其他值进行编码,在64位系统上的最高有效指针是2 ^ 48-1。

    如果最高的 14 位全为零,那么低 48 位保存的是一个指针,如果第 14 位置为 1,保存的便是一个整数。这让数字和指针在运算过程中变得十分快速。(最高的 14 位中,任意一位为 1,保存的便是整数)

    然后使用 15-17 位来编码其他立即数。

    总结一下,就是使用 int64 作为 JavaScript 运行的 var,这个 var 可以保存数字或者指针。

    代码在这里 qv4value_p.h



  • @qyvlik 厉害,都研究到v4引擎来了。那么,作为我们QML开发者,需要注意那些呢?想知道知道。👷



  • @jiangcaiyang123 这种应该是 tagged pointer 的原理。



  • @qyvlik 能具体介绍一下吗?好像还是不懂的样子…………


Log in to reply
 

走马观花

最近的回复

  • 由于我们在二次开发的过程中,需要采用调试来测试开发的效果,而使用cmake生成的Visual Studio项目,代码都是O2优化的,不太符合我们的需求,而我们必须每次都要载入Visual Studio 2017手动修改代码优化到禁用,这的确有一些麻烦,于是我们需要找一个更加便利的方法达到效果。我在稍微研究了一下之后得到结论:其实很好解决。

    准备环境

    Windows 10
    Visual Studio 2017
    Notepad++

    随便打开一个vcxproj文件,然后按下快捷键:Ctrl + F,转到文件查找一栏。按照下面的要求填写:

    文件类型 *.vcxproj 查找目标 <Optimization>MaxSpeed</Optimization> 替换为 <Optimization>Disabled</Optimization>

    然后点击“在文件中替换”,等待一会儿,就可以看到优化全部去掉了。这样就可以顺利地单步调试而不会出现断点下不了或者是其它问题了。
    替换代码优化

    read more
  • 惊讶图.jpg
    USD是一个正在发展过程中的文件格式,最基础的,能够支持网格、简单的材质、简单的光照。稍微复杂一点,就可能要借助后续的插件支持了。比如说骨骼动画,这个在USD之前的版本都是没有的,后面慢慢地得到了支持。它是通过UsdSkel这个模块支持的。这个算是和USD核心代码平级的,所以算是USD的外围插件。其实看USDSkel的发展,USDSkel其实是打算做一个动画的最小集,即仅仅支持骨骼和约束的功能,后面更加复杂的功能,通过修改UsdSkel的特性来实现。

    USD已经有一套完善的机制可以很方便地添加自定义的类型。这主要通过USD内置的usdGenSchema.py脚本来达到效果。usdGenSchema.py脚本所在的位置是:

    D:\Develop\USD\pxr\usd\lib\usd

    所以要让USD支持约束,可以选择自己通过Schema来规划一下约束这个类型,包括哪些属性。USD的说明符(specifier)包括class、def和over。其中class和C++的类很相似。我们要自己写一个Schema,大致的内容是这样:

    #usda 1.0 ( """ This file constains schema for supporting skeletal animations in USD. """ subLayers = [ @usdGeom/schema.usda@ ] ) over "GLOBAL" ( customData = { string libraryName = "usdRig" string libraryPath = "qtdream/usd/usdRig" } ) { } class Constraint "Constraint" ( inherits = </Imageable> ) { uniform asset target ( doc = """Target represent affectors whom the constraint will affect to.""" ) uniform asset[] targets ( doc = """The parent targets representing this constraint tied to.""" ) uniform float[] weights ( doc = """Optionally, weights can control the percentage the constraint is affected.""" ) uniform vector3f[] targetOffsetTranslates ( doc = """Optionally, we can specify translate offset to precisely adjust.""" ) uniform vector3f[] targetOffsetRotates ( doc = """Optionally, we can specify rotate offset to precisely adjust.""" ) uniform vector3f rotationDecompositionTarget ( doc = """Used in parentConsstraint.""" ) uniform bool useDecompositionTarget ( doc = """Used in parentConstraint.""" ) }

    接着要根据这个schema产生一大堆的代码,于是,编写以下的脚本:

    :: 运行UsdView插件.bat set Path=^ D:\Develop\Python27;^ D:\Develop\Python27\Scripts;^ D:\Develop\USD_Build\lib;^ D:\Develop\USD_Build\bin;^ D:\Develop\USD_Build\third_party\maya\lib;^ D:\Develop\Autodesk\Maya2018\bin;^ %Path% set MAYA_PLUG_IN_PATH=%MAYA_PLUG_IN_PATH%;^ D:\Develop\USD_Build\third_party\maya\plugin set PYTHONPATH=%PYTHONPATH%;^ D:\Develop\USD_Build\lib\python;^ D:\Develop\Autodesk\Maya2018\Python\Lib\site-packages set MAYA_SCRIPT_PATH=%MAYA_SCRIPT_PATH%;^ D:\Develop\USD_Build\third_party\maya\lib\usd\usdMaya\resources;^ D:\Develop\USD_Build\third_party\maya\plugin\pxrUsdPreviewSurface\resources set XBMLANGPATH=%XBMLANGPATH%;^ D:\Develop\USD_Build\third_party\maya\lib\usd\usdMaya\resources :: 需要安装Jinja2,否则会报错 pip install Jinja2 :: 开始定位到D盘目标位置上,然后执行脚本。 pushd D:\Develop\USD\qtdream\usd\lib\usdRig python D:\Develop\USD\pxr\usd\lib\usd\usdGenSchema.py schema.usda . popd

    如果出现了

    Traceback (most recent call last):
    File "D:\Develop\USD\pxr\usd\lib\usd\usdGenSchema.py", line 43, in <module>
    from jinja2 import Environment, FileSystemLoader
    ImportError: No module named jinja2
    错误,那么可能要想办法让python寻找到Jinja2。于是脚本中添加了:

    pip install Jinja2

    最后很高兴,顺利地生成了想要的C++文件,和产生的Schema文件。

    read more
  • USDView推出了插件的框架,可以顺利地编写Python脚本,作为插件让USDView载入。网上有一个高手,他在他的github上发布了自己的USDView插件。这个插件可不简单,他将USDView推出的插件架构活灵活用,并且添加了一些值得赞赏的效果:支持了USDView不曾支持的节点编辑功能。这个插件的名称叫usdNodeGraph。

    他的github地址在这里:

    https://github.com/1xinghuan/usdNodeGraph.git

    下面介绍一下如何使用吧。

    首先当然是把他的库拿下来了。推荐安装git,并且执行git clone放在本地。

    git clone git@github.com:1xinghuan/usdNodeGraph.git

    获取Qt.py库
    Qt.py库是统一Qt的版本用的。大家知道Qt4的时候有PySide,而Qt5有PySide2。我们在使用Python的时候,通常要执行 from PySide2.QtWidgets import QWidget

    等等脚本,而Qt.py将其统一起来了。不用你写PySide还是PySide2了。所以要执行下面的脚本:

    sudo pip install qt.py

    编写脚本支持其载入
    这个脚本和普通载入USDView插件差不多,唯一的不同是需要设置PYTHONPATH。因为它还要引入其它的库。脚本的内容是: #!/bin/sh export LD_LIBRARY_PATH=/usr/local/USD/lib64:$LD_LIBRARY_PATH export PYTHONPATH=$PYTHONPATH:/usr/local/USD/lib/python # 让usdView能够顺利地载入usdNodeGraph的地址 currentDir=$(cd `dirname $0`; pwd) export PXR_PLUGINPATH_NAME=$currentDir/usdNodeGraph/plugin export PYTHONPATH=$PYTHONPATH:/$currentDir/usdNodeGraph/lib/python:$currentDir/usdNodeGraph/plugin /usr/local/USD/bin/usdview $currentDir/model/7_29_1.usda

    保存文件,就可以顺利地执行了。其实还是挺简单的。执行后的效果如下:
    USDView结合usdNodeGraph.gif

    read more
  • 首先这是一个未知的旅程,有安装Maya软件有风险,一是因为它是商业软件,可能会有版权纠纷,二是Maya软件非常大,安装不慎,可能会出现各种奇怪的问题。我也是参考国外一篇文章才敢开始自己的Maya之路。至于遇到的问题,的确非常多,Maya依赖的版本太多,一些版本不一致的问题可能会导致很多诡异的问题,这时找Maya,找Autodesk是无济于事的。

    安装Maya的运行必备项

    tbb:Intel库,支持并行计算用,典型的是paralell_for用法。
    tiff:图像格式支持
    ssl:加密用
    png:图像格式支持
    gcc:编译器套件

    sudo apt-get install -y libtbb-dev libtiff5-dev libssl-dev libpng12-dev libssl1.0.0 gcc libjpeg62

    安装Alien

    因为Maya是rpm包,要转为deb包,就要借助alien了。alien的安装如下:

    sudo apt-get install -y alien elfutils

    安装多媒体库

    Maya的多媒体编辑功能依赖多媒体库,Linux最常见的就是gstreamer了。

    sudo apt-get install -y libaudiofile-dev libgstreamer-plugins-base0.10-0

    安装图形库

    Maya在Linux中,只有OpenGL是支持的(Maya这么古老的软件是不会这么快支持Vulkan的啦),所以也要安装。目前OpenGL的Linux实现是mesa。命令是:

    sudo apt-get install -y libglw1-mesa libglw1-mesa-dev mesa-utils

    这和安装Qt支持的图形库差不多,事实上Maya的GUI也是大部分依赖Qt。

    安装字体库

    Maya是极度依赖字体的,试想一下,在Linux字体那么丑,能看吗?当然不能。所以还是要安装合适的字体才行。命令是:

    sudo apt-get install -y xfonts-100dpi xfonts-75dpi ttf-mscorefonts-installer fonts-liberation

    在配置ttf-mscorefonts的时候,点击Ok和Yes就可以了。

    同时安装其它依赖Maya的包

    其余依赖Maya的包可以通过下面的命令安装。
    csh:c外壳命令行程序
    fam:Linux中计算机文件或者目录改变的观察者。一旦改变了执行通知操作。

    sudo apt-get install -y csh tcsh libfam0 libfam-dev xfstt

    安装xp6包

    cd /tmp
    wget http://launchpadlibrarian.net/183708483/libxp6_1.0.2-2_amd64.deb
    sudo dpkg -i libxp6_1.0.2-2_amd64.deb

    下载Maya2018

    你可以去Maya官网下载Maya2018,它有给出链接,下载应该不会遇到太多问题。
    然后解压Maya2018到合适的位置。
    我这里是:/media/jiangcaiyang/Data/软件安装包/Linux安装包/Maya2018

    安装Maya2018

    现在需要利用alien将所有rpm包转为deb包。

    sudo alien -cv *.rpm

    接着安装deb包

    udo dpkg -i *.deb

    掉包rpm,欺骗Maya并且让安装通过

    因为Maya的Linux安装包是给Redhat或者是CentOS开发的,所以默认rpm作为安装包的程序。对于debian系,它一直不认的,所以在运行带界面的程序的时候,总是出错。于是我们要执行一下欺骗,让rpm一直返回正确,这样才能欺骗Maya的安装包,让其安装通过。

    编写一个简单的C程序:

    echo "int main (void) {return 0;}" > mayainstall.c

    编译C程序

    gcc mayainstall.c

    备份rpm

    sudo mv /usr/bin/rpm /usr/bin/rpm_backup

    替换掉rpm

    sudo cp -v a.out /usr/bin/rpm

    对一些库位置建立软连接,让Maya识别到

    因为Maya的安装程序在Redhat或者是CentOS测试成功,而在Debian系不成功,对于处于Debian系的Deepin来说,还是挺麻烦的呢。因此还是要重新建立链接才行。

    sudo ln -s /usr/lib/x86_64-linux-gnu/libtbb.so /usr/lib/x86_64-linux-gnu/libtbb_preview.so.2
    sudo ln -s /usr/lib/x86_64-linux-gnu/libtiff.so /usr/lib/libtiff.so.3
    sudo ln -s /usr/lib/x86_64-linux-gnu/libssl.so /usr/autodesk/maya2018/lib/libssl.so.10
    sudo ln -s /usr/lib/x86_64-linux-gnu/libcrypto.so /usr/autodesk/maya2018/lib/libcrypto.so.10

    启动Maya 2018的安装包并且进行安装

    Maya 2018的安装包名称是setup,需要为此添加可执行的权限,因此要执行以下的命令:

    chmod +x setup
    然后执行之
    sudo ./setup
    之后就出现了Maya安装的界面了。久违了哈。
    Maya安装界面

    选择单机版,并且全部输入1。
    Maya安装全部输入1

    下个界面选择【继续】,然后就顺利地完成啦。点击【完成】
    Maya安装完成
    还没有完呢,还需要继续进行下一步的操作才行。

    对已经安装的Maya执行额外的操作

    首先是创建目录。

    sudo mkdir -p /usr/tmp
    给新建立的目录满权限
    sudo chmod 777 /usr/tmp

    为Maya创建一些配置目录。

    mkdir -p ~/maya/2018 ~/maya/2018/syncColor/Shared

    添加一句配置,解决Maya段错误

    echo "MAYA_DISABLE_CIP=1" >> ~/maya/2018/Maya.en

    运行命令解决颜色管理错误

    echo "LC_ALL=C" >> ~/maya/2018/Maya.env

    执行命令,递归地强制让~/maya给满权限。

    chmod -Rfv 777 ~/maya

    恢复扫尾工作

    还记得我们将rpm掉包了吗?现在恢复回来。

    sudo rm -v /usr/bin/rpm
    sudo mv -v /usr/bin/rpm_backup /usr/bin/rpm

    替换正版的Maya2018(选用)

    因为我们安装Maya2018的时候,序列号和产品密钥都是随便填写的1,但是如果是换用正版的Maya2018,我们需要将序列号填写为666-69696969,密钥填写为657J1,并且我们需要用正版的库替换掉我们自己安装的库。因此要执行下面的操作:

    sudo mv /usr/autodesk/maya2018/lib/libadlmint.so.14.0.23 /usr/autodesk/maya2018/lib/libadlmint.so.14.0.23_old
    sudo cp libadlmint.so.14.0.23 /usr/autodesk/maya2018/lib

    最后出现我们喜闻乐见的结果~
    Maya 2018的运行效果

    read more

关注我们

微博
QQ群