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

393 Views Asked by At

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!

1

There are 1 best solutions below

1
Chuck Walbourn On BEST ANSWER

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.

  • It seems to happen in both Debug and Release (optimized) configurations, and with both /fp:fast and /fp:precise.

  • This does not happen with x64 native code or with x86 if you use /arch:IA32.

  • I'm able to reproduce the same issue with VS 2017 (15.9.11) as well as VS 2019 (16.0.3).

#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.