这两天写的代码概率性的崩溃在 XMMatrixMultiply() 函数,XMMatrixMultiply() 本身是 inline 函数可以看到崩溃处的代码:

vX = _mm_mul_ps(vX,M2.r[]);

经查,_mm_mul_ps 是 SSE2 指令要求内存地址 16 字节对齐。猜想可能是字节未对齐引发的问题,打印出矩阵参数的地址,果然,发生崩溃时都是未对齐到 16 字节的情况。

XMMATRIX 声明中指定了对齐到 16 字节,如下:

__declspec(align()) struct XMMATRIX
{
...
};

但是显然没起到效果,继续查发现是用到 XMMATRIX 变量被定义成了类成员变量,该类的实例是 new 出来的:

class MyClass
{
XMMATRIX matrix_;
}; MyClass* ptr= new MyClass(); // 这里应该有一个编译警告

而 new 操作符只保证对齐到不大于 alignof(std::max_align_t)  也就是 8 字节,导致成员变量 matrix_ 也只能对齐到 8 字节。 解决方法先将成员变量 martix_ 赋值给一个局部变量,然后通过局部变量调用 XMMatrixMultiply() 函数。直接使用 new 会有一条对象可能无法对齐到 16 字节的警告信息,但因为我是用 std::make_shared 直接生成智能指针,编译器没能给出这条警告——这也是个坑,最终导致了前面的崩溃问题。

注意 XMMatrixMultiply() 的声明,第一个参数是值传参,第二个是引用传参,问题就处在引用传参上:

 typedef const XMMATRIX FXMMATRIX
typedef const XMMATRIX& CXMMATRIX; inline XMMATRIX XM_CALLCONV XMMatrixMultiply (FXMMATRIX M1, CXMMATRIX M2); //注意第二个参数是引用传参

MSDN 中对 XMMatrixMultiply 函数的声明和实际代码并不一致:

XMMATRIX XMMatrixMultiply(
[in] XMMATRIX M1,
[in] XMMATRIX M2
);

如果真的两个参数都是值传参也就没有字节对齐的问题了。

最终结论:XMMATRIX 结构体要求 16 字节对齐,只能用作局部变量或全局变量——在静态存储区或栈上分配内存可以确保 align(16) 声明有效,永远不要用 new 分配堆内存,也不要用作类成员变量;如果需要在成员变量中保存矩阵可以用 DirectX::XMFLOAT4X4 ,使用时再转换为 XMMATRIX 。

顺便吐槽一下,MSDN 以前被称为写得最好的开发文档是当之无愧的,现在只能呵呵了。最近两年新增的文档(比如 UWP 和 DX11 的文档)明显敷衍了事,函数说明经常一句话了事,看文档和直接对着函数声明猜用法都没什么区别了,这次居然还出现了函数声明不一致的情况,这样下去吃枣药丸哪。

UWP开发细节记录:DirectX::XMMATRIX 的坑的更多相关文章

  1. UWP开发细节记录:WRL::ComPtr 的坑

    WRL::ComPtr 取原始指针的地址有两种方式: operator&()   先释放原指针再取地址 GetAddressOf() 直接得到原始指针的地址 显然,operator& ...

  2. UWP开发细节记录:加载图像文件到D2D位图和D3D纹理

    在UWP中加载文件一般先创建 StorageFile 对象,然后调用StorageFile.OpenReadAsync 方法得到一个IRandomAccessStream 接口用来读取数据: Stor ...

  3. UWP开发细节记录:IStream 和 IRandomAccessStream^ 以及 IMFByteStream 互转

    IStream 和 IRandomAccessStream^ 互转 IRandomAccessStream^ --> IStream:  CreateStreamOverRandomAccess ...

  4. UWP开发细节记录:判断文件类型

    StorageFile.ContentType 属性,是 string 类型,用来表示文件内容的 MIME 类型.例如,音乐文件可能有 "audio/mpeg" MIME 类型.( ...

  5. 记UWP开发——多线程操作/并发操作中的坑

    一切都要从新版风车动漫UWP的图片缓存功能说起. 起因便是风车动漫官网的番剧更新都很慢,所以图片更新也非常慢.在开发新版的过程中,我很简单就想到了图片多次重复下载导致的资源浪费问题. 所以我给app加 ...

  6. PC客户端开发细节记录:保存GUID到VARIANT

    有两个 API 可以实现保存 GUID 到 VARIANT InitVariantFromGUIDAsBuffer 以字节数组形式保存,保存类型为 VT_ARRAY | VT_UI1,相当于字节拷贝, ...

  7. java后台开发细节记录

    1.  ResultMap是程序员控制SQL查询结果和实体类的映射关系,而不是sql语句中字段的重命名,所以在sql语句中还是要按照原来字段的格式进行书写.

  8. 讲讲我在Windows10(uwp)开发中遇到的一些坑.

    7月29日发布的Windows10正式版,当天安装好以后,在网络不太好的情况下,经过多次尝试终于装上了Visual Studio 2015和Windows 10 10240的SDK.这两周一直在开发U ...

  9. 领域驱动和MVVM应用于UWP开发的一些思考

    领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...

随机推荐

  1. centos6 Linux安装redis 2.6.14

    1.获取安装文件 wget http://download.redis.io/redis-stable.tar.gz 2.解压文件 tar xzvf redis-stable.tar.gz 3.进入目 ...

  2. MySQL数据导入到Mongo

    背景:如题干所述,需要将一份数据导入到mongo数据库,减少项目依赖的数据源. 解决方案: 使用mongo自带的mongoimport工具. 首先在test库里创建一个空集合:[import_test ...

  3. charles重复发包工具/repeat

    重复发包工具/repeat Charles 让你选择一个请求并重复,在测试后端接口的时候非常有用: Charles将请求重新发送到服务器,并将响应显示为新请求. 如果您进行后端更改并希望测试它们,用了 ...

  4. Android:一个高效的UI才是一个拉风的UI(二)

    趁今晚老大不在偷偷早下班,所以有时间继续跟大伙扯扯UI设计之痛,也算一个是对上篇<Android:一个高效的UI才是一个拉风的UI(一)>的完整补充吧.写得不好的话大家尽管拍砖~(来!砸死 ...

  5. Docker概念学习系列之Docker与传统虚拟机差异(4)

    不多说,直接上干货! 见[博主]撰写的https://mp.weixin.qq.com/s/YihjPONUcUi4b_7RC8oLYw   传统虚拟化是在硬件层面实现虚拟化,需要有额外的虚拟机管理应 ...

  6. 全网最详细的大数据集群环境下多个不同版本的Cloudera Hue之间的界面对比(图文详解)

    不多说,直接上干货! 为什么要写这么一篇博文呢? 是因为啊,对于Hue不同版本之间,其实,差异还是相对来说有点大的,具体,大家在使用的时候亲身体会就知道了,比如一些提示和界面. 安装Hue后的一些功能 ...

  7. JavaScript -- Screen

    -----041-Screen.html----- <!DOCTYPE html> <html> <head> <meta http-equiv=" ...

  8. 深入了解preventDefault与stopPropagation

    event.preventDefault()用法介绍(阻止默认事件) 该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作).例如,如果 type 属性是 "subm ...

  9. 【详解】JNI (Java Native Interface) (四)

    案例四:回调实例方法与静态方法 描述:此案例将通过Java调用的C语言代码回调Java方法. 要想调用实例对象的方法,需要进行以下步骤: 1. 通过对象实例,获取到对象类的引用  => GetO ...

  10. tomcat 虚拟目录

    在webapps同级目录 下建立一个webapps_abc的目录,将网站根目录abc文件夹放入webapps_abc目录下: 找到conf目录下的,server.xml文件,在service节点下添加 ...