c++matrixdirectxmultiplicationdirectxmath

DirectX::XMMATRIX Multiplication incorrect after function pass (C++)


I am having some trouble understanding why I am getting different results when multiplying two DirectX 4x4 matrices together, depending on whether the multiplication is performed within a class function or not.

Using identity matrices as an example, the values of result1 and result2 end up being different using the following code.

#include <iostream>
#include <DirectXMath.h>

using namespace DirectX;

class Model {
public:
    XMMATRIX MatrixMult(XMMATRIX test) {
        XMMATRIX result = test * XMMatrixIdentity();
        return result;
    }
private:
};

int main() {

    Model m;

    XMMATRIX result1 = XMMatrixIdentity() * XMMatrixIdentity(); //returns identity
    XMMATRIX result2 = m.MatrixMult(XMMatrixIdentity()); //doesn't return identity
    int height = 4;
    int width = 4;

    //Output results
    XMMATRIX results[2] = { result1, result2 };

    //for each result
    for (int res = 0; res < 2; ++res) {
        //for each row
        for (int i = 0; i < height; ++i)
        {
            //for each column
            for (int j = 0; j < width; ++j)
            {
                if (j == 0) {
                    std::cout << XMVectorGetX(results[res].r[i]) << ' ';
                }
                else if (j == 1) {
                    std::cout << XMVectorGetY(results[res].r[i]) << ' ';
                }
                else if (j == 2) {
                    std::cout << XMVectorGetZ(results[res].r[i]) << ' ';
                }
                else if (j == 3) {
                    std::cout << XMVectorGetW(results[res].r[i]) << ' ';
                }
            }
            std::cout << std::endl;
        }
        std::cout << "\n";
    }

    return 0;
    }

It actually looks like in result2, the expected result starts in row 3 of the matrix? (Output below)

//result1
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

//result2
8.2597e-39 -1.07374e+08 -1.07374e+08 -1.07374e+08
-1.07374e+08 -1.07374e+08 -1.07374e+08 -1.07374e+08
1 0 0 0
0 1 0 0

I know through passing the array as a function I am making a copy of it, but I wouldn't have thought that would make a difference here.

Any help would be greatly appreciated!


Solution

  • TL;DR: This is a compiler bug likely due to bad code-generation.

    The weird output happens only when using the x86 (32-bit) compiler, not when using the x64 (64-bit) native compiler. I tried a few different ways of outputting the results, and they are consistently weird for x86 but correct for x64.

    #include <iostream>
    #include <stdio.h>
    #include <DirectXMath.h>
    
    using namespace DirectX;
    
    class Model {
    public:
        XMMATRIX MatrixMult(XMMATRIX test) {
            XMMATRIX result = test * XMMatrixIdentity();
            return result;
        }
    private:
    };
    
    int main() {
    
        Model m;
    
        XMMATRIX result1 = XMMatrixIdentity() * XMMatrixIdentity(); //returns identity
        XMMATRIX result2 = m.MatrixMult(XMMatrixIdentity()); //doesn't return identity
        int height = 4;
        int width = 4;
    
        //Output results
    #if 0
        XMFLOAT4X4 mat[2];
        XMStoreFloat4x4(&mat[0], result1);
        XMStoreFloat4x4(&mat[1], result2);
    
        //for each result
        for (int res = 0; res < 2; ++res) {
            //for each row
            for (int i = 0; i < height; ++i)
            {
                printf("%f %f %f %f\n",
                    mat[res].m[i][0], mat[res].m[i][1], mat[res].m[i][2], mat[res].m[i][3]);
            }
        }
    #elif 0
        XMFLOAT4X4 mat[2];
        XMStoreFloat4x4(&mat[0], result1);
        XMStoreFloat4x4(&mat[1], result2);
    
        //for each result
        for (int res = 0; res < 2; ++res) {
            //for each row
            for (int i = 0; i < height; ++i)
            {
                //for each column
                for (int j = 0; j < width; ++j)
                {
                    std::cout << mat[res].m[i][j] << ' ';
                }
                std::cout << std::endl;
            }
            std::cout << "\n";
        }
    #else
        XMMATRIX results[2] = { result1, result2 };
    
        //for each result
        for (int res = 0; res < 2; ++res) {
            //for each row
            for (int i = 0; i < height; ++i)
            {
                //for each column
                for (int j = 0; j < width; ++j)
                {
                    if (j == 0) {
                        std::cout << XMVectorGetX(results[res].r[i]) << ' ';
                    }
                    else if (j == 1) {
                        std::cout << XMVectorGetY(results[res].r[i]) << ' ';
                    }
                    else if (j == 2) {
                        std::cout << XMVectorGetZ(results[res].r[i]) << ' ';
                    }
                    else if (j == 3) {
                        std::cout << XMVectorGetW(results[res].r[i]) << ' ';
                    }
                }
                std::cout << std::endl;
            }
            std::cout << "\n";
        }
    #endif
    
        return 0;
        }
    

    You should use Help -> Send Feedback -> Report a Problem... to report the bug. Be sure to mention it applies to both VS 2017 and VS 2019.