luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.
MIT License
567 stars 107 forks source link

Hardware-accelerated Matrix4x4f results are different from software results #145

Open EmVeeKee opened 4 years ago

EmVeeKee commented 4 years ago

Hello Luca,

First: really like the code!

When switching from x86 to x64 mode I noticed odd behavior in my CPU matrix operations. It turns out that on my laptop in x64 mode the hardware acceleration kicks in when multiplying Matrix4x4f (see opengl.net.math, matrix.cs, public static Matrix4x4f operator*(Matrix4x4f m, Matrix4x4f n) ).

"

if HAVE_NUMERICS

        if (Vector.IsHardwareAccelerated) {
            unsafe {
                Unsafe.Write(&r, Unsafe.Read<Mat4x4>(&m) * Unsafe.Read<Mat4x4>(&n));
            }
        } else {

endif

" However, the result of this multiplication is different from the code that is used in absence of hardware acceleration. And at least for me the 'software' version works.

Depending on using/not using the Mat4x4 hardware accelearated multiplication, I get the results below for a 'Scaled(0.5f, 0.5f, 1.0f) * Translated(3f, 3f, 3f)'. In the accelerated case I get the full translation (no scaling by 0.5f), in the software case I get the (for me) correct shift of 1.5f.

res = {||0.5, 0, 0, 0||0, 0.5, 0, 0||0, 0, 1, 0||3, 3, 3, 1||} res = {||0.5, 0, 0, 0||0, 0.5, 0, 0||0, 0, 1, 0||1.5, 1.5, 3, 1||}

        Matrix4x4f scale05 = Matrix4x4f.Identity;
        scale05.Scale(0.5f, 0.5f, 1.0f);            

        Matrix4x4f trans333 = Matrix4x4f.Translated(3f, 3f, 3f);
        Matrix4x4f res = scale05 * trans333;

        var x = Unsafe.Read<Mat4x4>(&scale05);
        var y = Unsafe.Read<Mat4x4>(&trans333);            
        var z = y * x;

Best regards,

Maarten

EmVeeKee commented 4 years ago

Looked into it a bit more. With a and b are both Matrix4x4f, then the software multiplication ab is identical to the hardware accelerated multiplication transpose(transpose(a) transpose(b)). Hence it seems that e.g. Unsafe.Read(&a) will effectively transform Matrix4x4f a into Mat4x4 transpose(a).

luca-piccioni commented 4 years ago

Thank you!

Evidently it means that arguments are intended as row-major matrices. Ouch.

Indeed we need to transpose 3x times? Maybe it's better to remove Numerics from Matrix*.

EmVeeKee commented 4 years ago

Hello Luca,

Removing the hardware acceleration (HAVE_NUMERICS from conditional compilation symbols) is the solution I have taken, as I do not need to do heavy lifting on the CPU.

Using Numerics is nice, but I see no easy solution. You cannot change the order of the coefficients in Matrix4x4f, as these are nicely matched to OpenGL.

I did not check whether the multiplication is still faster when using hardware acceleration and transposing, or by using something like ‘Matrix4x4f.ToMatrix4x4()’ that uses the Matrix4x4(Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single, Single)https://docs.microsoft.com/en-us/dotnet/api/system.numerics.matrix4x4.-ctor?view=netframework-4.8#System_Numerics_Matrix4x4__ctor_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_ constructor, and an additional constructor Matrix4x4f(Matrix4x4 src). This all feels a bit cumbersome, the original solution was neat, simple, but unfortunately broken.

Best regards,

Maarten

From: Luca Piccioni notifications@github.com Sent: Saturday, September 14, 2019 12:33 AM To: luca-piccioni/OpenGL.Net OpenGL.Net@noreply.github.com Cc: Maarten van Kampen maarten.van.kampen@asml.com; Author author@noreply.github.com Subject: Re: [luca-piccioni/OpenGL.Net] Hardware-accelerated Matrix4x4f results are different from software results (#145)

CAUTION: This message is from an external sender

Thank you!

Evidently it means that arguments are intended as row-major matrices. Ouch.

Indeed we need to transpose 3x times? Maybe it's better to remove Numerics from Matrix*.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fluca-piccioni%2FOpenGL.Net%2Fissues%2F145%3Femail_source%3Dnotifications%26email_token%3DANFYNPEZ7YLQ3DUPR2A6DUTQJQIKBA5CNFSM4IWPEDX2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6WLCKY%23issuecomment-531411243&data=01%7C01%7Cmaarten.van.kampen%40asml.com%7C861966e3a595428ef04b08d7389a588c%7Caf73baa8f5944eb2a39d93e96cad61fc%7C1&sdata=M1COlbkMvf17fVHSyCiCsvOuOJcsEgQ7HEX0Oh5CSuo%3D&reserved=0, or mute the threadhttps://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FANFYNPBED2PB3ZA72YORSMTQJQIKBANCNFSM4IWPEDXQ&data=01%7C01%7Cmaarten.van.kampen%40asml.com%7C861966e3a595428ef04b08d7389a588c%7Caf73baa8f5944eb2a39d93e96cad61fc%7C1&sdata=wqc%2B88zdw8TpoR2dZB04dCSo7rkhzfbRjnmgP2TuiI0%3D&reserved=0.

-- The information contained in this communication and any attachments is confidential and may be privileged, and is for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. Unless explicitly stated otherwise in the body of this communication or the attachment thereto (if any), the information is provided on an AS-IS basis without any express or implied warranties or liabilities. To the extent you are relying on this information, you are doing so at your own risk. If you are not the intended recipient, please notify the sender immediately by replying to this message and destroy all copies of this message and any attachments. Neither the sender nor the company/group of companies he or she represents shall be liable for the proper and complete transmission of the information contained in this communication, or for any delay in its receipt.