Matrix multiplication in shader goes nuts if it's not in a function

Hi,


I am multiplying two matrices in a shader utility function. In fact I'm multiplying quite a few matrices in this utility function to create a model view transformation. Everything works nicely, except for in one case where I have to multiply two matrices in a function. All this function does is take two float4x4s and multiply them together, if I don't do this, if I try to multiply them inline where I have the function the shader shows complete garbage. The matrices I'm multiplying are the post view space and a camera rotation matrix.


Everything works great, when those camera matrix multiplications are in a function. It makes no sense to me. Here are links to my code:


This is the useless function that is required looks like this:


float4x4 matrixProduct4x4(float4x4 m1, float4x4 m2) {
  return m1 * m2;
}



Here is where I have to use it:


  SRT_CR = matrixProduct4x4(SRT_C, cameraRotationMatrix.y);
  SRT_CR = matrixProduct4x4(SRT_CR, cameraRotationMatrix.x);


^^^ This works.


If try this:


    SRT_CR = SRT_C * cameraRotationMatrix.y;
    SRT_CR = SRT_CR * cameraRotationMatrix.x;


Which is all that function does, I see garbage.


I don't understand what's happening. What is there being a function involved doing? You can see there are lots of other regular matrix multiplications happening without any problem, including other rotations that use the exact same rotation matrix format.


It seems like a Metal bug. Either the bug is that my code is broken and it shouldn't work with the function, or the bug is that it should work without the function.


Edit: I tried to post links to github but it ended up being in moderation, if anyone wants more details maybe I can provide those.


Thank you.

What is the type of

cameraRotationMatrix
? If it's a vector (say, a
float4
), then in the working case, you're implicitly constructing a
float4x4
with the value of
cameraRotationMatrix.y
on the diagonal, whereas in the non-working case, every element in the matrix is being multiplied by that value instead. I suspect that if you explicitly construct a matrix by writing, for example,
SRT_CR = SRT_C * float4x4(cameraRotationMatrix.y)
, the behavior will be the same as when you call the function.

I'm sorry, it's not clear from my example code what the types are. cameraRotationMatrix is a struct where x, y and z are rotation matrices, that is float4x4.


The type of cameraRotationMatrix is RotationMatrix:


struct RotationMatrix {
  float4x4 x;
  float4x4 y;
  float4x4 z;
};


So it isn't the case that calling the function is creating a diagnoal matrix. Both SRT_C and cameraRotationMatrix.y are float4x4.


In the case of `y` I create the following rotation matrix:


float4x4 rotateY(float4 angles) {
  
  float cosY = cos(angles.y);
  float sinY = sin(angles.y);
  
  return float4x4(float4(cosY, 0, sinY, 0), float4(0, 1, 0, 0), float4(sinY * -1, 0, cosY, 0), float4(0, 0, 0, 1));
}


Thank you.

Thanks for clarifying. This may in fact be a compiler bug. Could you please file a Radar at http://bugreport.apple.com (with your project attached) and let me know the bug number?

Hi wcm, Thank you for your reply. I have filed a ticket via the URL you provided. The bug number is 28489181. I've included instructions. Please let me know if you need any additional information. Thank you!

Thanks for the report; we'll take a look.

I should note that when I switched from a packed_float3 to an unpacked float3 for the rotation value storage that this problem resolved for me and it was no longer necessary for me to use the function. I feel though that if there was a problem in my code between using packed and unpacked types that it should have been broken regardless of me using the function. I will add this note to the issue as well. Thank you!

Matrix multiplication in shader goes nuts if it's not in a function
 
 
Q