Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiplication order is changing from HLSL to SPIR-V #956

Closed
Cry-Mory opened this issue Jan 4, 2018 · 4 comments
Closed

Multiplication order is changing from HLSL to SPIR-V #956

Cry-Mory opened this issue Jan 4, 2018 · 4 comments
Labels
spirv Work related to SPIR-V

Comments

@Cry-Mory
Copy link

Cry-Mory commented Jan 4, 2018

Title

Multiplication order is changed when HLSL is compiled to SPIR-V

Functional Impact

It completely changes the result of multiplication as it is not commutative.

Minimal repro steps

  1. Download the following vertex shader:
    AuxGeom.AuxTextVS_AuxTextVS_hlsl.txt

  2. Compile it using dxc by executing: 'dxc.exe -spirv .\AuxGeom@AuxTextVS_AuxTextVS.hlsl -T vs_5_0
    -E AuxTextVS' (Generated SPIR-V text can be found here:
    generate_spirv_code.txt).

Expected result

I expect to get the same order of multiplication.

Actual result

The order of multiplication is changed. In other words, in HLSL we have the following multiplication:

OUT.pos=mul(cbAuxGeom.matViewProj,IN.pos);

which is compiled to the following SPIR-V multiplication:

%25 = OpLoad %v4float %in_var_POSITION
%73 = OpLoad %mat4v4float %72
%76 = OpVectorTimesMatrix %v4float %25 %73

Further technical details

I can understand that DirectX is always using row-major memory layout. A vector is usually encountered as a row and multiplication is usually mul(vec, matrix) and this needs to be changed in SPIR-V case, that is why the compiler is switching the orders but this is not a general rule. In CryEngine, the order of multiplication is usually the same as Vulkan SPIR-V which is mul(matrix, vec). So, the order does not need to change.

I think the best solution is to have a command line option to force switching the order in multiplication or not.

@antiagainst
Copy link
Contributor

The swap of operands is actually a side effect of how matrix types are handled in SPIR-V CodeGen. See the doc for details. Basically, a HLSL MxN matrix (M rows and N columns) is translated into a SPIR-V matrix with M vectors and each vector has N elements (M columns and N rows). So each matrix is conceptually represented as its transpose. To keep consistency, we need to swap the operands.

This way of translation is kinda confusing, but it gets everything correct and works. DXC is consistent with glslang in handling matrices. See also KhronosGroup/glslang#433 and KhronosGroup/glslang#789 for related discussions.

@Cry-Mory
Copy link
Author

Cry-Mory commented Jan 4, 2018

Thanks a lot for your reply. I packed matrices in row-major order (-Zpr) to fix the issue.

@Cry-Mory Cry-Mory closed this as completed Jan 4, 2018
@antiagainst
Copy link
Contributor

@Cry-Mory: Glad it helps! :) Just wanted to let you know that right now -Zpr/-Zpc is just ignored. Only row_major/column_major in the source code are respected. But it will be fixed soon in #961.

@antiagainst antiagainst added the spirv Work related to SPIR-V label Mar 17, 2018
@zopsicle
Copy link

zopsicle commented Mar 4, 2025

If I understand correctly, the following happens:

  • HLSL column-major matrices become SPIR-V row-major matrices.
  • HLSL mul(a, b) becomes SPIR-V as if GLSL b * a.

And the justification for this is that it simplifies 1D subscripting of a matrix (i.e. row = matrix[row_index]).

While this preserves runtime semantics of HLSL (that is, matrices are column-major, and c = mul(a, b) corresponds to the mathematical formula C = AB) at runtime, giving the correct results, it informs tools that inspect shaders wrong. For example, RenderDoc displays buffer contents transposed because it sees a row-major annotation in the SPIR-V shader.

A command-line flag that instructs DXC to, instead of the above two rules, instead generate more complicated code for matrix subscripting, would therefore still be useful IMO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
spirv Work related to SPIR-V
Projects
None yet
Development

No branches or pull requests

3 participants