zoukankan      html  css  js  c++  java
  • UWP开发细节记录:DirectX::XMMATRIX 的坑

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

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

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

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

    __declspec(align(16)) 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() 的声明,第一个参数是值传参,第二个是引用传参,问题就处在引用传参上:

    1 typedef const XMMATRIX FXMMATRIX
    2 typedef const XMMATRIX& CXMMATRIX;
    3 
    4 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 的文档)明显敷衍了事,函数说明经常一句话了事,看文档和直接对着函数声明猜用法都没什么区别了,这次居然还出现了函数声明不一致的情况,这样下去吃枣药丸哪。

    作者:小时了了
    原创文章,欢迎转载,但请以链接形式注明本文地址.
  • 相关阅读:
    数据库事务隔离级别
    impala jdbc4的group by语句的bug,加上limit没错
    火狐不支持innerText属性,只支持innerHTML属性
    struts2.x + Tiles2.x读取多个xml 配置文件
    ids for this class must be manually assigned before calling save():Xxx
    整合ssh model $$_javassist_13 cannot be cast to javassist.util.proxy.Proxy
    火狐点击链接请求两次的问题
    C++——类和动态内存分配
    C++——使用类
    C++——对象和类
  • 原文地址:https://www.cnblogs.com/xrunning/p/5247409.html
Copyright © 2011-2022 走看看