November 20, 2017

Windows 下重定向当前进程的 stdout 到网络连接

前段时间碰到一个需求,想把当前进程的标准输出重定向到一个 tcp 连接上。

如果依照 posix 标准,调用一下 dup2 这个 api 就能搞定,但是 windows 并不是基于 posix 标准的操作系统,所以做起来要麻烦的多。

我在 stackoverflow 和 msdn 上找了一番,没有看到什么靠谱的做法,所以自己折腾了一天。这里的难点在于:windows 上虽然有 _dup2 来模拟 posix 的 api dup2 ,但 fd 在 windows 上并不是内核对象, HANDLE 才是。fd 是在 runtime 层模拟出来的东西。msdn 上引用最多的一篇是:Creating a Child Process with Redirected Input and Output ,做的事情是创建一个子进程,然后重定向标准输入输出。

重定向子进程和重定向当前进程有什么区别?我是这样理解的:

Windows 虽然也有标准输入输出的概念,但是是基于 HANDLE 的。GetStdHandle 和 SetStdHandle 两个 API 虽然可以读写 Windows 的标准输入输出句柄,但这个句柄似乎(我猜想)是在 runtime 初始化阶段绑定到 fd 0 1 2 上的,之后,基于 fd 的一套 runtime 机制都不再经过这个转换过程。在进程运行过程中,调用 SetStdHandle 并不能重定向 C 的标准输入输出库。

阅读全文 "Windows 下重定向当前进程的 stdout 到网络连接" »

November 09, 2017

四元数的压缩存储

今天在读 https://github.com/guillaumeblanc/ozz-animation 这个动画库的代码时,发现它使用了一个有趣的四元数压缩技术。

我们用四元数来表示 3D 空间中的旋转,通常需要 4 个浮点数。不过用四元数表示旋转时,四元数通常会先做一次归一化,即 x*x + y *y + z*z + w*w = 1 。所以我们只需要保留 x,y,z 和 w 的符号位就够了。

但三个 float 来表示四元数既然有压缩余地。这是因为用来表示旋转量时, float 提供的 23 bit 精度是多余的。 1/2^23 的转角在视觉上完全是忽略不计的。而且 x,y,z 都一定小于 1 ,所以 float 的指数位也浪费了 1bit 。

ozz-animation 这个库采用了一个有趣的方法来做进一步压缩。

阅读全文 "四元数的压缩存储" »

October 31, 2017

skynet 1.1.0 发布

skynet 1.1 正式发布了。

这个版本的意义主要在于修补了一年前 2016 年 7 月发布 1.0 以来已经发现的 bug 。受益于 skynet 被越来越多的项目使用,很多我们自己使用时未能发现的 bug 通过 github 被定位和修复。

在这个版本中, lua 版本同步到了最新的 5.3.4 并打上了官方发布的 5 个 bugfix ,其中有几个还是我们在使用 skynet 时发现并汇报给 lua 官方的。jemalloc 也更新到了 5.0.1 。有同学报告说在某些测试环境下,jemalloc 的第 5 版性能比前一个版本要差,但我认为随着版本更新,性能有所下降是正常的。只要项目没有大的分叉,使用新的稳定版本都是值得的。

不过 skynet 的这个新版本在 IO 方面应该是比旧版本有性能提高。因为 1.1 版中,网络写操作会尝试先在 IO 线程之外完成。在需要做大量数据发送的场合(例如做流媒体广播),性能会有明显的提升。

1.1 版的 lua 模块放进了专门的名字空间下,这点可能会造成一定的对 1.0 版的兼容性问题。不过长远看,在工程方面是有利的,修改老项目适配 1.1 版的成本也不大。

还有一些小的改进,具体可见 HISTORY.md ,基本都向前兼容。建议还在维护的使用 skynet 1.0 的项目都应尽可能更新到 1.1 版。

October 26, 2017

近期在 bgfx 上做的一些工作

这段时间玩 bgfx ,除了前段公布的 lua binding 外,还颇做了一些别的工作。

首先是帮 bgfx 的 directx 12 driver 打了补丁,使之可以用 mingw build 出来正确运行。也就是之前 blog 上提到的 Direct3D12 的接口设计 bug 。这个 pr 已经被官方接纳。

然后是我给 bgfx 的 debug text 做了中文的支持。 bgfx 专门做了一个层,模拟 VGA 的 text mode 。一开始我学着过去 dos 模式下做中文系统的方式增加了双字节支持,采用在模拟出来的 video memory 的 attribute byte 上设置几个特殊标记来表示接下来的两个 slot 是连起来的一个 unicode 字符。

这种让一个汉子占据两个 video memory slot 的方式在过去非常常见,不过弊端也很明显:容易产生半个汉字乱码问题,解决方案看起来比较 trick 。而且把汉字作为一种特殊字符来处理,而不是彻底解决 unicode 大字符集的解决方案感觉也很不美观。

最开始提交的 pr 果不其然被拒了

接下来我花了一点气力实现一个更加通用的 unicode 方案:

至少要支持多个 code page , 并把原本就支持的 dos 字符集当作 cp437 ,而可以由使用者执行添加新的 codepage ,比如汉字所用的 cp936 。再将不同的 codepage 统一转换为 unicode 。我为多 codepage 编写了一个简单的查找 cache ,字形贴图管理的新模块。cp936 里用到 15 点阵汉字字形是从文泉驿黑体中导出的。另外为了更好的支持 unicode ,把 virtual video memory 里保存 codepoint 的单字节扩展为 3 字节,可以把单个汉字放在一个 slot 里。不过,为了排版正确,还是需要在 debug print 的 api 中检测到汉字就在每个汉字后保留一个空格,让单个汉子占两个英文字符的位置。

这个 patch 现在可以在 bgfx 里使用 ,不过尚未合并到主干。看起来作者也没有拒掉,目前还留在 open 的 pr 列表中。

阅读全文 "近期在 bgfx 上做的一些工作" »

October 25, 2017

给 Lua 在 windows 下换上 utf-8 文件名支持

最近在 windows 做开发比较多,lua 原生库使用的都是 C 标准库中的函数,比如文件操作就是用的 fopen 打开文件。这对 unicode 支持的很糟糕。我希望所有和文件名打交道的地方都使用 utf-8 编码,所以今天花了一点时间实现了这么一个库。

我把 lua 原生库中和文件名有关的 api 都重新实现了一遍,包括了:loadfile , dofile , os.rename , os.remove , os.execute, os.getenv , 以及 io.open 。除了 require 都可以在接口上使用 utf-8 字符串了。这里 require 是偷懒没支持 :)

阅读全文 "给 Lua 在 windows 下换上 utf-8 文件名支持" »

October 21, 2017

BGFX 的一个 lua 封装库

前两年有同学给我推荐了 BGFX 这个库,第一眼被它吸引是它的口号:"Bring Your Own Engine/Framework" style rendering library 。这动不动就说自己是 3d engine 的时代,好好做好一个渲染库,仅仅做好渲染库,是多难得的一件事情。

今年国庆节的时候,偶然间我又翻到这个仓库,居然作者一直在更新。坚持了五年,一直在维护这么个小玩意,让我对这个项目多了点信心。节后我饶有兴趣的研究了一下它的代码。

现在我觉得,这个库的设计思想非常对我的胃口,核心部分几乎没有多余的东西:数据计算、平台 API 支持、数据持久化格式支持、等等都没有放在核心部分。它仅仅只做了一件事:把不同平台的图形 API :Direct X 、OpenGL 等等整合为一套统一的接口,方便在此基础上开发跨平台的 3d 图形程序。不同平台的 3d api 的差异,正是 3d 游戏开发中最脏最累的活了。

阅读全文 "BGFX 的一个 lua 封装库" »

September 20, 2017

Direct3D12 的接口设计 bug

昨天被 D3D12 的一个 bug 坑了一晚上,这个问题很值得一写。

最初是发现 LUID ID3D12Device::GetAdapterLuid() 这个函数有问题。我用 mingw64 gcc 编译后的程序,只要调用了一个 api ,d3d12device 设备对象的虚函数表就被破坏掉了。下一次对这个设备的任何 api 调用都会 crash 掉。

由于这个函数的实现在 d3d12.dll 中,是没有源码的,所以只能用 gdb 调试了一下。发现了一个问题:这个 api 的返回值是 LUID ,它是一个结构体。C/C++ 函数返回结构体是没有统一的调用规范的,按道理 COM 的实现应该避免设计这种 API 。

按 COM 的规定,所有 API 必须返回 HRESULT ,只有少量例外可以返回 ULONG 整数。其实之前的 D3D 版本在设计类似 API 的时候都符合了这个约定,例如 D3D9 就有一个类似的 API :

HRESULT GetAdapterLUID( [in] UINT Adapter, [in] LUID *pLUID )

阅读全文 "Direct3D12 的接口设计 bug " »

Misc

Categories

Archives

Recent Comments